Только вот использовать их в такой комбинации невозможно в принципе. Если точнее:
два явных импорта с одним именем конфликтуют;
если конфликтует явный импорт и use module::*;, всегда используется явный;
если явного нет, а глоб-импортов, содержащих это имя, больше одного, всегда выдаётся ошибка.
Что в совокупности значит, что в любой точке программы имя типа/трейта всегда однозначно сопоставляется конкретному трейту, и сигнатура для этого сопоставления значения не имеет.
Если вы и правда считаете что это лишняя ифнормация и можно сделать лучше, откройте pre-RFC обсуждение на IRLO, я думаю там вам смогут привести куда более веские аргументы.
А при чём здесь, собственно, internals и pre-RFC? Мы же обсуждаем не изменение языка, а то, как имеющимися фичами языка наиболее точно выразить трейт Map крейта dashmap, нет? Если уж здесь что-нибудь и имело бы смысл открывать, так это PR в dashmap, рефакторящий его на другой вариант… но я не уверен, стоит ли лезть со внутренним рефакторингом без намерения становиться долгосрочным контрибьютором.
Кроме того, теперь запись (...) и (...) это совершенно разные вещи...
Нет, не разные, по-прежнему Key (K) в скоупе и Self::Key — это независимые типы (хотя да, строчка type Key = Key; будет выглядеть забавно).
… и переименование генериков в библиотеке становится ломающим изменением (по этим же причинам).
Во-первых, это не генерики, а ассоциированные типы. Во-вторых, да, в отличие от генериков они именованные и это не бага, это фича. Использование вместо них генериков — это как out-параметры: порой так делают, но обычно это считается не особо идеоматичным.
И разница как раз в том, что
… зато теперь нельзя сразу понять, сколько параметров.
Понять можно и параметров здесь — кроме типа, для которого он реализован — нет. И на мой взгляд так правильнее, чем вводить искусственные параметры, которые для заданного целевого типа всё равно обязаны иметь одно-единственное значение.
Для сравнения давайте посмотрим в стандартную библиотеку на пару похожих трейтов: AsRef и Deref. У обоих есть единственный метод с одинаковой сигнатурой fn(&Self) -> &Something. Тем не менее, они принципиально отличаются. AsRef имеет параметр типа, что позволяет ему иметь много реализаций. Один и тот же строковый тип String удовлетворяет сразу многим конкретным реализациям: AsRef<[u8]>, AsRef<str>, AsRef<OsStr>, AsRef<Path> — и это только в стандартной библиотеке. Deref же параметров не имеет, а имеет взамен ассоциированный тип. Для каждого типа, реализующего Deref, жёстко задано, в какой именно тип он переводит (и в случае String это именно str). У пользователя нету выбора, какую именно реализацию использовать.
Вот этот служебный трейт Map, на мой взгляд, ближе ко второму варианту. Логика его использования не предусматривает вариант, в котором один и тот же тип имеет несколько реализаций, различающихся параметрами, из которых пользователь выбирает нужную — а именно в этом и есть разница.
Вообще, я бы сказал на первый взгляд, что лишнее здесь всё, кроме 'a и M — просто потому, что трейт Map определён неправильно. K, V, S должны бы быть ассоциированными типами, а не параметрами.
Параметры имеют смысл в основном тогда, когда реализаций с несколькими параметрами может быть несколько… но я очень сильно сомневаюсь в структуре, для которой имели бы смысл реализации Map с разными K, V, S.
По-моему, все планы с полётом на Марс и возвращением кораблей (а тем более людей) подразумевают разворачивание там завода по производству топлива. Обсуждаемая программа этого не подразумевает.
Ключевых момента в этой таблице два. Во-первых, автор утверждает, что полностью заправленный Starship на орбите имеет 9.5 км/с запаса скорости (delta V), что, по его оценкам, недостаточно для перелёта к Луне, посадки, взлёта и возвращения на Землю. Отсюда необходимость дозаправки на окололунной орбите, следовательно, возникает танкер, который тоже нужно заправлять на околоземной орбите.
Во-вторых, "после дозаправки". Автор оценивает количество топлива, выводимое одним Starship, в 100 тонн (заявленная полезная нагрузка на низкую околоземную орбиту) и приходит к выводу, что каждая дозаправка на орбите — это десяток запусков танкеров, а не дозаправка от одного танкера, как в красивых демо-видео. Соответственно, в случае Марса "после дозаправки" — это тот же десяток запусков.
Забавно, мой vim 8.2 номер инода не меняет никогда. Возможно, какие-то детали настроек — у меня он практически без кастомных настроек, я им не пользуюсь особо.
Рискну предположить, что у тех, у кого не воспроизводится, редактор пишет изменённый код в новый файл, который затем переименовывает поверх старого (чтобы гарантировать атомарность обновления). В таком случае у баша останется дескриптор старого файла, содержимое которого не менялось.
Замену в чём именно? В идеале предполагается заменить им LLVM для дебаг-билдов, потому что производительность LLVM — один из ключевых факторов, ограничивающих скорость их сборки.
Можно ли написать на Расте бэкенд с производительностью кода не хуже, чем у LLVM? Зависит от того, сколько человеко-лет в него вложить...
Я не так много вращался в Джаве и довольно много (но колхозно) вращаюсь в Шарпе, но мне, черт побери, нравится многословность и CamelCase. Это сделано для людей, а все остальное решает IntelliSense и нормально спроектированные библиотеки.
Лично мне кажется, что одним из критериев полноценного языка программирования является возможность сравнительно эффективно читать и писать код на этом языке без средств поддержки, конкретно под этот язык заточенных.
Без фанатизма – всё-таки подсветка синтаксиса сильно облегчает жизнь, не говоря уже про нормальную работу с отступами – но это вещи, которые умеет любой приличный редактор кода. А вот автодополнение и всплывающие подсказки типов уже должны бы быть опциональны для эффективной работы.
Не говоря уже про языки, обязывающие использовать единственную фирменную IDE, наподобие какого-нибудь там LabVIEW.
До тех пор, пока они локализованы, можно обойтись крейтами, собирающими и подключающими отдельные ассемблерные файлы. Quickstart для ARM не требует ночника.
Вот для чего потребуется nightly-версия — так это для тех архитектур, для которых недоступен собранный крейт core. Вот для его сборки, в первом приближении, обязательна nightly-версия.
Так в том-то и дело, что меня вполне устроит в качестве ответа линтер, который банит потенциально корректный код. Если он скажет "написанный так код потенциально опасен, так нельзя, пользуйтесь абстракцией такой-то" — оно и к лучшему. Если мне действительно будет нужно — найду в документации, как разрешить данное конкретное нарушение правил линтера (а заодно прочитаю, чем именно оно опасно, на что именно нужно проверить код вручную и о чём нужно предупредить комментарием следующего разработчика).
Не устраивает меня ситуация, в которой "разумеется, C++ позволяет всё это безопасно написать, но чтобы быть уверенным хотя бы на 90% в безопасности написанного, обязательно необходим ревьюер с опытом в современном C++ от N лет". Новые проекты в опенсорсе нередко начинаются с одного человека (или маленькой команды), и я не понимаю, как сейчас начать проект на современном C++ без хождения по всем стандартным граблям с нуля.
Только вот использовать их в такой комбинации невозможно в принципе. Если точнее:
use module::*;, всегда используется явный;Что в совокупности значит, что в любой точке программы имя типа/трейта всегда однозначно сопоставляется конкретному трейту, и сигнатура для этого сопоставления значения не имеет.
А при чём здесь, собственно, internals и pre-RFC? Мы же обсуждаем не изменение языка, а то, как имеющимися фичами языка наиболее точно выразить трейт Map крейта dashmap, нет? Если уж здесь что-нибудь и имело бы смысл открывать, так это PR в dashmap, рефакторящий его на другой вариант… но я не уверен, стоит ли лезть со внутренним рефакторингом без намерения становиться долгосрочным контрибьютором.
Вообще-то запрещает, можете проверить сами :-)
Нет, не разные, по-прежнему Key (K) в скоупе и Self::Key — это независимые типы (хотя да, строчка
type Key = Key;будет выглядеть забавно).Во-первых, это не генерики, а ассоциированные типы. Во-вторых, да, в отличие от генериков они именованные и это не бага, это фича. Использование вместо них генериков — это как out-параметры: порой так делают, но обычно это считается не особо идеоматичным.
И разница как раз в том, что
Понять можно и параметров здесь — кроме типа, для которого он реализован — нет. И на мой взгляд так правильнее, чем вводить искусственные параметры, которые для заданного целевого типа всё равно обязаны иметь одно-единственное значение.
Для сравнения давайте посмотрим в стандартную библиотеку на пару похожих трейтов:
AsRefиDeref. У обоих есть единственный метод с одинаковой сигнатуройfn(&Self) -> &Something. Тем не менее, они принципиально отличаются.AsRefимеет параметр типа, что позволяет ему иметь много реализаций. Один и тот же строковый типStringудовлетворяет сразу многим конкретным реализациям:AsRef<[u8]>,AsRef<str>,AsRef<OsStr>,AsRef<Path>— и это только в стандартной библиотеке.Derefже параметров не имеет, а имеет взамен ассоциированный тип. Для каждого типа, реализующегоDeref, жёстко задано, в какой именно тип он переводит (и в случаеStringэто именноstr). У пользователя нету выбора, какую именно реализацию использовать.Вот этот служебный трейт
Map, на мой взгляд, ближе ко второму варианту. Логика его использования не предусматривает вариант, в котором один и тот же тип имеет несколько реализаций, различающихся параметрами, из которых пользователь выбирает нужную — а именно в этом и есть разница.Я не вполне понял постановку вопроса. Это три разных варианта того, как можно было бы сделать один и тот же трейт?
Вот потому я и говорю, что у трейта изначально неоптимальное определение, на мой взгляд.
Примерно вот так
если там дальше пробем не возникнет.
Не "магически вывелись", а прописаны как ассоциированные типы в трейте Map и его реализации. Примерно вот так:
если вообще не сделать параметром тип M, а не эти три по отдельности.
Вообще, я бы сказал на первый взгляд, что лишнее здесь всё, кроме 'a и M — просто потому, что трейт Map определён неправильно. K, V, S должны бы быть ассоциированными типами, а не параметрами.
Параметры имеют смысл в основном тогда, когда реализаций с несколькими параметрами может быть несколько… но я очень сильно сомневаюсь в структуре, для которой имели бы смысл реализации Map с разными K, V, S.
Увы, да — я открыл себе исходный код на посмотреть когда-нибудь потом, не подумав, что это должно бы быть задокументировано.
По-моему, все планы с полётом на Марс и возвращением кораблей (а тем более людей) подразумевают разворачивание там завода по производству топлива. Обсуждаемая программа этого не подразумевает.
Ключевых момента в этой таблице два. Во-первых, автор утверждает, что полностью заправленный Starship на орбите имеет 9.5 км/с запаса скорости (delta V), что, по его оценкам, недостаточно для перелёта к Луне, посадки, взлёта и возвращения на Землю. Отсюда необходимость дозаправки на окололунной орбите, следовательно, возникает танкер, который тоже нужно заправлять на околоземной орбите.
Во-вторых, "после дозаправки". Автор оценивает количество топлива, выводимое одним Starship, в 100 тонн (заявленная полезная нагрузка на низкую околоземную орбиту) и приходит к выводу, что каждая дозаправка на орбите — это десяток запусков танкеров, а не дозаправка от одного танкера, как в красивых демо-видео. Соответственно, в случае Марса "после дозаправки" — это тот же десяток запусков.
Забавно, мой vim 8.2 номер инода не меняет никогда. Возможно, какие-то детали настроек — у меня он практически без кастомных настроек, я им не пользуюсь особо.
Самый простой способ проверки, что именно делает редактор:
если inode изменяется, то редактор заменил старый файл новым; если остаётся прежним — отредактировал файл на месте.
А я о чём:
./ OPEN test.sh
./ CREATE sedGpzLhh
./ OPEN sedGpzLhh
./ ACCESS test.sh
./ ATTRIB sedGpzLhh
./ ATTRIB sedGpzLhh
./ CLOSE_NOWRITE,CLOSE test.sh
./ MODIFY sedGpzLhh
./ CLOSE_WRITE,CLOSE sedGpzLhh
./ MOVED_FROM sedGpzLhh
./ MOVED_TO test.sh
./ OPEN test.sh
./ CREATE .test.sh.swp
./ OPEN .test.sh.swp
./ CREATE .test.sh.swx
./ OPEN .test.sh.swx
./ CLOSE_WRITE,CLOSE .test.sh.swx
./ DELETE .test.sh.swx
./ CLOSE_WRITE,CLOSE .test.sh.swp
./ DELETE .test.sh.swp
./ CREATE .test.sh.swp
./ OPEN .test.sh.swp
./ MODIFY .test.sh.swp
./ MODIFY .test.sh.swp
./ ATTRIB .test.sh.swp
./ CLOSE_NOWRITE,CLOSE test.sh
./ OPEN test.sh
./ ACCESS test.sh
./ CLOSE_NOWRITE,CLOSE test.sh
./ OPEN,ISDIR
./ CLOSE_NOWRITE,CLOSE,ISDIR
./ OPEN,ISDIR
./ CLOSE_NOWRITE,CLOSE,ISDIR
./ OPEN,ISDIR
./ CLOSE_NOWRITE,CLOSE,ISDIR
./ MODIFY .test.sh.swp
./ MODIFY .test.sh.swp
./ OPEN test.sh
./ MODIFY test.sh
./ ATTRIB test.sh
./ CLOSE_WRITE,CLOSE test.sh
./ ATTRIB test.sh
./ MODIFY .test.sh.swp
./ CLOSE_WRITE,CLOSE .test.sh.swp
./ DELETE .test.sh.swp
Извините, gedit не проверю — у меня Plasma, он не установлен.
(промахнулся местом ответа)
Рискну предположить, что у тех, у кого не воспроизводится, редактор пишет изменённый код в новый файл, который затем переименовывает поверх старого (чтобы гарантировать атомарность обновления). В таком случае у баша останется дескриптор старого файла, содержимое которого не менялось.
Замену в чём именно? В идеале предполагается заменить им LLVM для дебаг-билдов, потому что производительность LLVM — один из ключевых факторов, ограничивающих скорость их сборки.
Можно ли написать на Расте бэкенд с производительностью кода не хуже, чем у LLVM? Зависит от того, сколько человеко-лет в него вложить...
Лично мне кажется, что одним из критериев полноценного языка программирования является возможность сравнительно эффективно читать и писать код на этом языке без средств поддержки, конкретно под этот язык заточенных.
Без фанатизма – всё-таки подсветка синтаксиса сильно облегчает жизнь, не говоря уже про нормальную работу с отступами – но это вещи, которые умеет любой приличный редактор кода. А вот автодополнение и всплывающие подсказки типов уже должны бы быть опциональны для эффективной работы.
Не говоря уже про языки, обязывающие использовать единственную фирменную IDE, наподобие какого-нибудь там LabVIEW.
До тех пор, пока они локализованы, можно обойтись крейтами, собирающими и подключающими отдельные ассемблерные файлы. Quickstart для ARM не требует ночника.
Вот для чего потребуется nightly-версия — так это для тех архитектур, для которых недоступен собранный крейт
core. Вот для его сборки, в первом приближении, обязательна nightly-версия.Cranelift-бэкенд потихоньку прогрессирует, кстати.
Так в том-то и дело, что меня вполне устроит в качестве ответа линтер, который банит потенциально корректный код. Если он скажет "написанный так код потенциально опасен, так нельзя, пользуйтесь абстракцией такой-то" — оно и к лучшему. Если мне действительно будет нужно — найду в документации, как разрешить данное конкретное нарушение правил линтера (а заодно прочитаю, чем именно оно опасно, на что именно нужно проверить код вручную и о чём нужно предупредить комментарием следующего разработчика).
Не устраивает меня ситуация, в которой "разумеется, C++ позволяет всё это безопасно написать, но чтобы быть уверенным хотя бы на 90% в безопасности написанного, обязательно необходим ревьюер с опытом в современном C++ от N лет". Новые проекты в опенсорсе нередко начинаются с одного человека (или маленькой команды), и я не понимаю, как сейчас начать проект на современном C++ без хождения по всем стандартным граблям с нуля.