Здравствуйте, Cyberax, Вы писали:
C>Если мне хотелось бы изгибаться — я бы взял динамический язык.
Ну тогда макросы Раста слишком гибки — немедленно выпиливаем их, ведь есть динамические языки.
C>В Расте есть перегрузка операторов. А явное указание трейтов позволяет, например, разделять публичный интерфейс и реализацию.
Не понял. Можно мысль развернуть?
C>Так что не нужно включать в каждый файл пару миллионов строк Буста. C>В результате, код на Rust'е строится что-то в 20 раз быстрее С++-ного.
Буст тут вообще к чему? И зачем его в каждый файл включать?
А для ускорения помогает модульность, а не "указание трейтов".
C>Это игрушка, где настоящее-то? С поддержкой полной форматной строки. В теории оно возможно, но что-то мне подсказывает, что компиляторы это пока ниасиливают.
Нашел несколько реализаций. Признаюсь, глубоко не копал. В стандарте нет, да. Но что значит "компиляторы не осиливают"?
Они (некоторые, по крайней мере) даже стандартный принтф проверять осилили.
C>Уже можно. Хотя не очень понятно зачем. Ну и макросы действуют только в пределах файла при явном их импорте, так что не стоит преувеличивать их глобальность.
Понятно зачем. Чтобы это был нормальный языковый инструмент, а не как в С, где макросам префикс либы лепят.
C>А какие реальные плюсы от их необязательности?
По моему, мы ходим по кругу. Ну не "наследует"/реализует тип нужный трейт, но нужные операции там имеются. Всё могло бы работать, но не в расте. Только не надо рассказывать, что одноимённые функции/операторы могут делать совсем разные вещи в разный трейтах. Могут, но это бывает ещё реже, а уж чтобы создавало проблемы с темплейтами так вообще редкость.
C>Нет, высказвалось мнение, что шаблоны С++ лучше за счёт того, что делают вычисления во времени компиляции. В С++ это единственный метод.
Во первых, не единственный (constexpr ещё).
Во вторых, мнение высказывал не я.
В третьих, не собираюсь отрицать, что сложные вычисления выглядят страшно и нормальные макросы лучше. Но шаблоны не только для этого.
C>Можно по нему делать PM и практически повторить стандартный механизм исключений. На практике, опять же, практически никогда не нужен.
В смысле пусть функция возвращает Ани а там будет или результат или "исключение"? Ну это коряво и не слишком естественно.
"Стандартные" Option/Result куда лучше в этом плане.
C>Но и не особо много.
Но есть.
C>Возможная неоднозначность и изменение поведения. Т.е.: C>
C>Какая функция вызовется? А если раскомментировать первую (в одном из включаемых файлов)?
В первом случае, я бы предпочёл неоднозначность и ошибку на этапе компиляции. В С++ так и происходит.
Если раскомментировать, то понятно что вызовется. И почему это удивительно? В конце концов, в коде типа такого тоже совершенно непонятно, что будет делать вызов (мало ли кто и что там переопределил!):
void test(some_interface *i)
{
i->do_work();
}
И точно так же новый код может "поломать" старый.
C>Необязательно. Первый параметр в Rust может указываться вручную, как и в Питоне. Так что этот вызов будет аналогичен: Ord::min(a, b). Если нужна конкретная спецификация, то можно так: f64::min(11, 12).
С питоном слабо знаком, можно чуть подробнее? "Ord" тут имя класса или неймспейс? И чем второй вызов отличается?
C>Именно так. И потому 90% возможностей С++ стоит выкинуть нафиг, оставив только то, что реально нужно.
Это только твоё мнение. Из Pаста тоже многое можно повыкидывать и без ущерба к надёжности. Если фантазировать, то из С++ было бы отлично повыкидывать всякие кривости имеющиеся из-за обратной совместимости. А вот возможности (модули, нормальные макросы, рефлексию и т.д.) наоборот добавить неплохо было бы.
Да и если на другие языки посмотреть — они тоже развиваются и увеличивают количество фич. Тот же С# скоро по "сложности" догонит С++ (если уже не обогнал).
C>С каждой фичей матрица их взаимодействий растёт квадратично. В результате, сейчас С++ полностью не может знать никто.
Ложное утверждение. Во первых, не все фичи взаимодействуют. Во вторых, в Расте фич гораздо больше, чем в С. Тем не менее язык получается "надёжнее" и удобнее.
C>И тех, которые могут заменить С++? Таких не знаю.
Не прикидывайся, что не понял. (Практически?) любую фичу можно выкинуть и язык всё равно может быть успешным.
C>То есть? GNOME написан на стандартном чистом C. Там объектная модель сделана полностью на ручных vtbl.
Изначально ты говорил про расширения языка. Они — непереносимы.
"Рукопашные реализации" без расширений переносимы, но имеют другие недостатки.
C>Что "ну-ну"? ООП на чистом С делается без проблем — это совершенно неоспоримый факт.
За указателями можно самому следить и "килер-фича" раста "не нужна" — неоспоримый факт такого же уровня.
Хватит передёргивать и выдирать из контекста. Давай ещё раз — хочешь спорить с тем, что встроенные в язык решения не лучше/удобнее/проще непонятных реализаций? Особенно если в языке отсутствуют инструменты упрощающие такие вещи (типа макросов).
Re[39]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, DarkEld3r, Вы писали:
C>>В Расте есть перегрузка операторов. А явное указание трейтов позволяет, например, разделять публичный интерфейс и реализацию. DE>Не понял. Можно мысль развернуть?
В С++ компилятор _обязан_ иметь полное тело шаблона при каждом его инстанцировании. Так как ошибка может возникнуть в любом месте шаблона, если у его параметра не окажется нужного метода.
В Rust каждый generic может компилироваться отдельно — всё что нужно сделать компилятору, это просто подставить адреса реальных функций, реализующих trait'ы. В этом Rust похож на C#, где то же самое делается на уровне байт-кода.
C>>Так что не нужно включать в каждый файл пару миллионов строк Буста. C>>В результате, код на Rust'е строится что-то в 20 раз быстрее С++-ного. DE>Буст тут вообще к чему? И зачем его в каждый файл включать?
Ну вот подключил ты тот же самый Boost.Xpressive — и сразу же затянулось примерно 100000 строк include'ов. В Rust'е у меня подтянется только внешний модуль из пакета regex (300 строк, не считая пустых и комментариев).
DE>А для ускорения помогает модульность, а не "указание трейтов".
Каким образом модульность будет помогать с шаблонами С++? Эксперимент с "extern template" показал, что сильно шаблоны ускорить таким образом нельзя.
DE>Нашел несколько реализаций. Признаюсь, глубоко не копал. В стандарте нет, да. Но что значит "компиляторы не осиливают"? DE>Они (некоторые, по крайней мере) даже стандартный принтф проверять осилили.
Стандартный printf проверяется в качестве специального случая, в виде магии компилятора. А вот полный разбор форматной строки и проверка совпадения типов параметров — пока нигде не делается.
C>>Уже можно. Хотя не очень понятно зачем. Ну и макросы действуют только в пределах файла при явном их импорте, так что не стоит преувеличивать их глобальность. DE>Понятно зачем. Чтобы это был нормальный языковый инструмент, а не как в С, где макросам префикс либы лепят.
В С макросы часто попадают во внешний интерфейс, т.е. если я объявлю макрос min, использую его в .h-файле (пользуясь случаем, хочу передать привет windows.h), то все пользователи .h-файла будут материться. В Rust это исключено — макрос будет действовать на уровне единицы трансляции.
Возможно столкновение имён макросов, но на практике маловероятно. Нет фундаментальных причин, запрещающих делать namespace для макросов, просто оно пока разработчикам не нужно.
C>>Можно по нему делать PM и практически повторить стандартный механизм исключений. На практике, опять же, практически никогда не нужен. DE>В смысле пусть функция возвращает Ани а там будет или результат или "исключение"? Ну это коряво и не слишком естественно.
Нет, можно ловить fail по Any.
C>>Какая функция вызовется? А если раскомментировать первую (в одном из включаемых файлов)? DE>В первом случае, я бы предпочёл неоднозначность и ошибку на этапе компиляции. В С++ так и происходит.
Не всегда происходит. В случае с double/float — да. А вот в случае с раскомментированием int — нет.
DE>Если раскомментировать, то понятно что вызовется. И почему это удивительно? В конце концов, в коде типа такого тоже совершенно непонятно, что будет делать вызов (мало ли кто и что там переопределил!) DE>И точно так же новый код может "поломать" старый.
Нет. В случае с виртуальной функцией код поломается, если изменится именно реализация виртуальной функции. Это нормально. В случае с добавлением реализации frob() сломается совершенно посторонний код.
Далее, в Rust серьёзно относятся к модульной компиляции. Предположим, что у нас есть модуль clink. Он использует модуль bling, внутри которого определена функция "frob(double)". Послезавтра в модуль bling добавили "frob(int)" — нужно ли в этом случае перекомпилировать clink? Если нужно, то как это обнаружить? А что если этот модуль binary-only?
C>>Необязательно. Первый параметр в Rust может указываться вручную, как и в Питоне. Так что этот вызов будет аналогичен: Ord::min(a, b). Если нужна конкретная спецификация, то можно так: f64::min(11, 12). DE>С питоном слабо знаком, можно чуть подробнее? "Ord" тут имя класса или неймспейс? И чем второй вызов отличается?
Ord — это имя трейта ('Ordered'). Второй вариант — это вызов непосредственной реализации.
C>>Именно так. И потому 90% возможностей С++ стоит выкинуть нафиг, оставив только то, что реально нужно. DE>Это только твоё мнение. Из Pаста тоже многое можно повыкидывать и без ущерба к надёжности.
А вот нельзя. Всё что можно выкинуть, уже почти выкинули. Пару лет назад там были зависимые типы, глобальный GC и т.п.
DE>Да и если на другие языки посмотреть — они тоже развиваются и увеличивают количество фич. Тот же С# скоро по "сложности" догонит С++ (если уже не обогнал).
В C# стараются не добавлять кривых фич, чтобы "лишь бы було". И начали с того, что взяли и выкинули 90% C++. И это работает, кстати.
C>>С каждой фичей матрица их взаимодействий растёт квадратично. В результате, сейчас С++ полностью не может знать никто. DE>Ложное утверждение. Во первых, не все фичи взаимодействуют.
Да ну? Можешь рассказать как будет работать "private virtual blah() volatile const"?
DE>Во вторых, в Расте фич гораздо больше, чем в С. Тем не менее язык получается "надёжнее" и удобнее.
Фундаментальных фич — не так сильно больше.
C>>И тех, которые могут заменить С++? Таких не знаю. DE>Не прикидывайся, что не понял. (Практически?) любую фичу можно выкинуть и язык всё равно может быть успешным.
В нише системных языков?
C>>То есть? GNOME написан на стандартном чистом C. Там объектная модель сделана полностью на ручных vtbl. DE>Изначально ты говорил про расширения языка. Они — непереносимы.
Расширения я упоминал только для RAII (__attribute(cleanup)__ из GCC/Clang). Всё остальное делается стандартным C.
DE>Хватит передёргивать и выдирать из контекста. Давай ещё раз — хочешь спорить с тем, что встроенные в язык решения не лучше/удобнее/проще непонятных реализаций? Особенно если в языке отсутствуют инструменты упрощающие такие вещи (типа макросов).
Да, встроенные в язык решения часто хуже библиотечных.
Sapienti sat!
Re[40]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>В Rust каждый generic может компилироваться отдельно — всё что нужно сделать компилятору, это просто подставить адреса реальных функций, реализующих trait'ы. В этом Rust похож на C#, где то же самое делается на уровне байт-кода.
Теперь понял о чём ты. А оптимизироваться/инлайниться при этом будет одинаково?
C>Каким образом модульность будет помогать с шаблонами С++? Эксперимент с "extern template" показал, что сильно шаблоны ускорить таким образом нельзя.
Как минимум, тем что хедеры не будут 100500 раз парситься.
Признаюсь честно — не особо вчитывался в описание модулей в С++. Тем не менее, заявлено ускорение и для темплейтов. Возможно, просто из-за того, что одни и те же инклюды не будут 100500 раз парситься.
В любом случае, я готов платить временем компиляции за производительность в рантайме (и дополнительную гибкость).
C>Возможно столкновение имён макросов, но на практике маловероятно. Нет фундаментальных причин, запрещающих делать namespace для макросов, просто оно пока разработчикам не нужно.
Что-то я не понял. Ты же сам нахваливал растовский принтф, который является макросом? Вполне пример внешнего интерфейса. В таком случае "столкновение имён" просто дело времени.
C>Не всегда происходит. В случае с double/float — да. А вот в случае с раскомментированием int — нет.
И это правильно. Неоднозначности ведь нет.
C>Нет. В случае с виртуальной функцией код поломается, если изменится именно реализация виртуальной функции. Это нормально. В случае с добавлением реализации frob() сломается совершенно посторонний код.
Не вижу существенной разницы.
C>Далее, в Rust серьёзно относятся к модульной компиляции. Предположим, что у нас есть модуль clink. Он использует модуль bling, внутри которого определена функция "frob(double)". Послезавтра в модуль bling добавили "frob(int)" — нужно ли в этом случае перекомпилировать clink? Если нужно, то как это обнаружить? А что если этот модуль binary-only?
В других языках это как-то решают.
C>А вот нельзя. Всё что можно выкинуть, уже почти выкинули. Пару лет назад там были зависимые типы, глобальный GC и т.п.
Да ладно. Если поискать, наверняка, что-то найдётся. К сожалению, с языком практически не знаком, так что сам привести примеры не смогу.
C>В C# стараются не добавлять кривых фич, чтобы "лишь бы було".
Да ладно? Давай заглянем в тему про С#6
От синтаксического сахара скоро что-нибудь слипнется.
Опасная это тенденция: чем больше всяких разных таких фишек, тем сложнее читать код неподготовленному человеку, тем медленнее изучение языка.
И тем проще написать плохо читаемый и ещё хуже работающий код.
Хотя, некоторые вещи и правда полезные, даже странно, что их сразу не сделали.
Кстати, перегрузка функция в С# есть...
C>И начали с того, что взяли и выкинули 90% C++. И это работает, кстати.
Заодно выкинули то из-за чего С++ вообще нужен. Язык получился абсолютно другой.
C>>>С каждой фичей матрица их взаимодействий растёт квадратично. В результате, сейчас С++ полностью не может знать никто. DE>> Ложное утверждение. Во первых, не все фичи взаимодействуют. C>Да ну?
Ну да. Не надо вырывать из контекста.
C>Можешь рассказать как будет работать "private virtual blah() volatile const"?
Что конкретно интересует?
В С# "private protected" тоже забавно смотрится.
C>Фундаментальных фич — не так сильно больше.
Тем не менее, больше. Да и сами фичи "более навороченные", по сравнению с простым до примитивности С.
Ну и дальше ты демагогией занимаешься.
DE>>Хватит передёргивать и выдирать из контекста. Давай ещё раз — хочешь спорить с тем, что встроенные в язык решения не лучше/удобнее/проще непонятных реализаций? Особенно если в языке отсутствуют инструменты упрощающие такие вещи (типа макросов). C>Да, встроенные в язык решения часто хуже библиотечных.
Опять передёргивание. Если в язык встроена нормальная возможность к расширению, то да, предпочтительнее библиотечное решение. Если нет, то рукодельные варианты будут уступать или производительностью или читабельностью или и тем и другим.
Re[41]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, DarkEld3r, Вы писали:
C>>В Rust каждый generic может компилироваться отдельно — всё что нужно сделать компилятору, это просто подставить адреса реальных функций, реализующих trait'ы. В этом Rust похож на C#, где то же самое делается на уровне байт-кода. DE>Теперь понял о чём ты. А оптимизироваться/инлайниться при этом будет одинаково?
Да, есть возможность LTO — link time optimization, как и в С/C++.
C>>Каким образом модульность будет помогать с шаблонами С++? Эксперимент с "extern template" показал, что сильно шаблоны ускорить таким образом нельзя. DE>Как минимум, тем что хедеры не будут 100500 раз парситься.
И всё. Больше улучшений не планируется.
DE>В любом случае, я готов платить временем компиляции за производительность в рантайме (и дополнительную гибкость).
Тут уже есть примеры, когда Rust был быстрее кода на С++ за счёт более умного решения.
DE>Что-то я не понял. Ты же сам нахваливал растовский принтф, который является макросом? Вполне пример внешнего интерфейса. В таком случае "столкновение имён" просто дело времени.
println! — это пример системного макроса (их штук 10 всего), он включается в каждый файл автоматически. Остальные макросы должны подключаться явно самим пользователем.
C>>Нет. В случае с виртуальной функцией код поломается, если изменится именно реализация виртуальной функции. Это нормально. В случае с добавлением реализации frob() сломается совершенно посторонний код. DE>Не вижу существенной разницы.
Существенная разница в том, что добавление совершенно левого кода ломает не относящийся к нему код.
C>>Далее, в Rust серьёзно относятся к модульной компиляции. Предположим, что у нас есть модуль clink. Он использует модуль bling, внутри которого определена функция "frob(double)". Послезавтра в модуль bling добавили "frob(int)" — нужно ли в этом случае перекомпилировать clink? Если нужно, то как это обнаружить? А что если этот модуль binary-only? DE>В других языках это как-то решают.
В каких? Я их не знаю. В чистом С нет перегрузки функций. В C#/Java нет раздельной компиляции. Что ещё у нас остаётся?
C>>И начали с того, что взяли и выкинули 90% C++. И это работает, кстати. DE>Заодно выкинули то из-за чего С++ вообще нужен. Язык получился абсолютно другой.
Ага. А в Rust выкинули так, чтобы всё равно можно было использовать его как системный язык.
C>>Можешь рассказать как будет работать "private virtual blah() volatile const"? DE>Что конкретно интересует?
Их взаимодействие и что курил автор этого куска Стандарта.
C>>Да, встроенные в язык решения часто хуже библиотечных. DE>Опять передёргивание. Если в язык встроена нормальная возможность к расширению, то да, предпочтительнее библиотечное решение. Если нет, то рукодельные варианты будут уступать или производительностью или читабельностью или и тем и другим.
Встроенные в язык фичи означают, что у языка недостаточная выразительность, чтобы сделать их удобными библиотечными.
Sapienti sat!
Re[42]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>Да, есть возможность LTO — link time optimization, как и в С/C++.
В С++ темплейты всё-таки могут легко инлайнится без привлечения линкера.
C>Тут уже есть примеры, когда Rust был быстрее кода на С++ за счёт более умного решения.
Кодегенерация для регэкспов? Ну да, хороший пример. Только это ведь возможно не из-за дополнительных ограничений генериков, а наоборот за счёт более мощной возможности (макросы).
C>println! — это пример системного макроса (их штук 10 всего), он включается в каждый файл автоматически. Остальные макросы должны подключаться явно самим пользователем.
Подключаться должны именно макросы? Не модули/либы их экспортирующие?
Если второе, то вполне вероятны конфликты. Если первое, то получше так как можно будет обойти, но тоже удобным это сложно назвать.
C>Существенная разница в том, что добавление совершенно левого кода ломает не относящийся к нему код.
Да нет существенной разницы. В худшем случае, оба вараинта вызовут проблемы.
Ну и я ни разу не сталкивался с такой проблемой с перегрузкой. Честно говоря, даже сложно представить когда это может вылезти, да ещё и так, чтобы было не очевидно.
C>Если нужно, то как это обнаружить?
Можно с модулем какие-то метаданные иметь.
C>В C#/Java нет раздельной компиляции.
Разве дотнетовские "сборки" (assembly) — это не то?
C>В чистом С нет перегрузки функций.
В С11 есть _Generic.
C>Их взаимодействие и что курил автор этого куска Стандарта.
Вроде, всё логично: констом ты объявляешь, что не будешь менять состояние класса внутри, а volatile говорит, что оно всё-таки может поменяться извне. Единственная практическая польза, которую вижу — компилятор даст по рукам при попытке всё-таки изменить что-то внутри метода.
Насчёт "что курил автор" — подозреваю просто для полноты добавили, примерно как протектед наследование. Проблемы в этом не вижу. Впрочем, я и просто volatile методы очень редко видел.
C>Встроенные в язык фичи означают, что у языка недостаточная выразительность, чтобы сделать их удобными библиотечными.
Тем не менее, совсем без встроенных фич не обойтись. Ну и популярные библиотечные решения часто в стандарт попадают.
Ну и злосчастную перегрузку функций ты вряд ли библиотекой добавишь.
Re[27]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
I>>Из твоих примеров совершенно не ясно, как получить цепочку вида x().y().z()
_>Так тебе надо цепочку или функцию вида "promise<Document> GetDocument()"? А то ты вроде как заказывал именно её в описание к тому API. Я потому и спрашиваю, что никак не могу понять что ты собственно хочешь увидеть.
Я хочу увидеть аналог x().y().z()
_>Если же говорить про цепочку, то чем тебе не нравится последовательность из .then().then()?
Это не то, что я просил. По существу, сравни две строки
1й это очевидный отстой, и я думал, что это не нужно объяснять, но у тебя наверняка своё видение и десятикратное увеличение кода не помеха
Напоминаю, x, y и z в либе объявлены вот так —
function x(success, error) {}
Как видишь, обычные колбеки. а вызвать цепочку надо вот так x().y().z()
I>>Далее, раз дело в метапрограммировании, ты не показал, как же именно будет генерироваться такой код
_>Я же говорил уже, что метапрограммирование не является обязательным для такого кода. Оно позволяет всего лишь перевести динамические вызовы (по виртуальным функциям) в статические, которые оптимизатор может заинлайнить и т.п.
Ты лучше покажи хоть одно решение, что бы выдавало именно то, что я просил. Не надо больше обших слов — или показывый или просто ничего не пиши, всё ведь и так ясно
I>>Ты сказал, что D классное метапрограммирование. И шота пока не ясно, как же сделать мой пример, который в джаваскрипте работает сам собой.
_>Ну да, в D оно сильнее чем в C++. А уже того, что есть в C++ достаточно для написание того же Sprit'a (который является примером реализации статического похода для подобных цепочек, хотя и не связанных с асинхронностью). Правда в C++ Spirit уже написан, а в D пока нет...
Неинтересный аргумент, это общие слова.
_>Что касается JS, то интересно, есть ли для него хоть одна нормальная реализация сопрограмм? )
Разумеется, как stackless так и stackfull. Осенью ты уже задавал этот же вопрос, кстати говоря. Воспользуйся поиском.
Сегодня в 8 вечера по Москве Scott Meyers выступит с загадочной речью "The Last Thing D Needs". Онлайн-трансляцию можно будет посмотреть здесь: http://www.ustream.tv/channel/dconf-2014
Затем будет выступление бородатой женщины про написанный на D JIT-компилятор JS, потом другие акробаты, клоуны и жонглеры.
Это сейчас в логове Фейсбука проходит DConf 2014: http://dconf.org/2014/schedule/
Я вчера первые три выступления посмотрел, трансляция очень качественно сделана. В онлайне было около 150 зрителей, в аудитории раза в 3-4 меньше.
Все это будет потом на ютюбе, но позже.
Re[42]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, FR, Вы писали:
_>>Так в pdf'ке же вроде весь код есть. Там описан printf, который кидает исключения в случае любых несоответствий строки форматирования аргументам.
FR>Это не то настоящий суровый printf должен практически все ошибки отлавливать во время компиляции, например как в OCaml: FR>...
Ну так это уже будет совсем другая функция с другим прототипом — там первым параметром должно идти что-то типа constexpr. На D естественно пишется без проблем. Ну а на C++ теоретически тоже можно поизвращаться, но будет очень криво из-за отсутствия возможности передавать строки как параметры шаблонов.
Re[42]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
_>>Ну я с этим собственно и не спорил, хотя бы уже потому, что не претендую на какие-то знания макросов Rust'a. C>Ну вот как раз кто-то спорил
Не помню тут критических отзывов о них. )
_>>Так в pdf'ке же вроде весь код есть. Там описан printf, который кидает исключения в случае любых несоответствий строки форматирования аргументам. C>Там описано, что так сделать можно, но конкретного кода нет. Я в целом вполне верю, что это возможно, но вот на constexpr и шаблонах сделать полный разбор строки printf — совсем нетривиально.
Не, там был как раз конкретный код (на странице 21). Только там разбор то идёт в рантайме (а иначе и не возможно для функции с прототипом как у printf, не переделывая первый параметр на что-то типа constexpr), так что вообще никаких сложностей нет.
А вот сделать разбор во время компиляции на C++ действительно очень не просто из-за его ограничений работы со строками в шаблонах (соответственно на D эта задачка решается элементарно). Однако подобные извращённые решения я тоже видел... Только там строку соответственно надо по странному задавать (макросом например и т.п.), т.е. это не прямая замена нормальному printf'у.
_>>Не очень понятно как это сделать, ведь gettext будет возращать обычную строку, а не что-то вроде constexpr. C>Будет специальная функция, назовём её "T" с такой сигнатурой: "fn T(initial: str) -> &'static str". Т.е. в программе будет что-то типа: "println!(T("Hello, world"), ...)". Макрос println! будет знать про то, что T будет возвращать исходную строку и для проверки валидности форматной строки просто возьмёт её аргумент. Ну а во время исполнения оно будет работать всё как обычно.
C>Ещё, вместо hard-coded имени T можно сделать специальную аннотацию на функцию.
Хы, модно. Такие вещи уже действительно только макросами делаются (если действительно делаются — я пока не видел сам, а верю на слово), а не метапрограммированием на шаблонах.
Re[43]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, DarkEld3r, Вы писали:
C>>Да, есть возможность LTO — link time optimization, как и в С/C++. DE>В С++ темплейты всё-таки могут легко инлайнится без привлечения линкера.
Только вот далеко не всегда это надо. В Rust есть опциональная возможность добавить force_inline аннотацию, кстати.
C>>Тут уже есть примеры, когда Rust был быстрее кода на С++ за счёт более умного решения. DE>Кодегенерация для регэкспов? Ну да, хороший пример. Только это ведь возможно не из-за дополнительных ограничений генериков, а наоборот за счёт более мощной возможности (макросы).
В Rust нет причин, по которым generics будут сильно тормознее С++. Ну разве что, сейчас в кодогенераторе многое ещё не оптимизировано.
C>>println! — это пример системного макроса (их штук 10 всего), он включается в каждый файл автоматически. Остальные макросы должны подключаться явно самим пользователем. DE>Подключаться должны именно макросы? Не модули/либы их экспортирующие?
Да, именно макросы. Выглядит так:
//Подключаем макрос из внешней библиотеки на стадию разбора синтаксиса
#[phase(syntax)]
extern crate regex_macros;
В соседнем файле этот макрос может и не подключаться.
C>>Существенная разница в том, что добавление совершенно левого кода ломает не относящийся к нему код. DE>Да нет существенной разницы. В худшем случае, оба вараинта вызовут проблемы.
Где?
DE>Ну и я ни разу не сталкивался с такой проблемой с перегрузкой. Честно говоря, даже сложно представить когда это может вылезти, да ещё и так, чтобы было не очевидно.
Я встречался.
C>>Если нужно, то как это обнаружить? DE>Можно с модулем какие-то метаданные иметь.
Каким образом? А что если нет исходников?
C>>В C#/Java нет раздельной компиляции. DE>Разве дотнетовские "сборки" (assembly) — это не то?
Не то.
C>>В чистом С нет перегрузки функций. DE>В С11 есть _Generic.
Оно работает на заранее перечисленных типах. Это не перегрузка.
DE>Насчёт "что курил автор" — подозреваю просто для полноты добавили, примерно как протектед наследование. Проблемы в этом не вижу. Впрочем, я и просто volatile методы очень редко видел.
Ну вот С++ весь такой. И D тоже приближается к нему.
C>>Встроенные в язык фичи означают, что у языка недостаточная выразительность, чтобы сделать их удобными библиотечными. DE>Тем не менее, совсем без встроенных фич не обойтись. Ну и популярные библиотечные решения часто в стандарт попадают.
Стандартная библиотека, если она не в виде компиляторной магии, — это не проблема.
DE>Ну и злосчастную перегрузку функций ты вряд ли библиотекой добавишь.
И не надо.
Sapienti sat!
Re[28]: Язык D - действительно красота и эффективность в одном ф
I>1й это очевидный отстой, и я думал, что это не нужно объяснять, но у тебя наверняка своё видение и десятикратное увеличение кода не помеха
Безусловно второй вариант красивее. Однако это единственное их отличие. Т.е. если у нас есть реализация для then, то это полностью решает твою задачу. А все твои претензии сводятся уже не к возможности решения, а к красоте, т.е. по сути синтаксическому сахару.
Что касается синтаксического сахара... На C++ сделать точную копию данного кода конечно не просто. Точнее это легко делается для глобальных функций. Получится что-то вроде "x()|y|z;" (просто переопределяем оператор | для future и засовываем then туда). Однако для функций-членов (как в твоём примере) это будет выглядеть заметно страшнее, типа "x()|XR::y|YR::z;", так что наверное лучше обычным then'ом обойтись и не мутить лишнего сахара.
А вот на D, благодаря наличию в нём перегрузки оператора вызова функции-члена, можно в одну строчку реализовать синтаксический сахар в точности, как ты хочешь.
Re[44]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Cyberax, Вы писали:
C>Только вот далеко не всегда это надо.
А когда это может мешать?
Ну и запретить тоже можно.
C>В Rust есть опциональная возможность добавить force_inline аннотацию, кстати.
И оно заинлайнит, если исходников нет?
C>В Rust нет причин, по которым generics будут сильно тормознее С++. Ну разве что, сейчас в кодогенераторе многое ещё не оптимизировано.
Во первых, "сильно" понятие растяжимое. Так можно заявить, что "нет причин, по которым компиляция С++ кода будет сильно тормознее".
Во вторых, речь шла про возможности, а не скорость.
C>Я встречался.
Можешь рассказать подробнее?
Желательно с уточнением насколько сложно и долго это было обнаружить.
C>Каким образом? А что если нет исходников?
Что-то типа комовских "type libraries", наверное, можно сделать.
Ну и вон с длл-ками либ-файлы тоже нужны. В чём проблема так дополнительную информацию хранить?
C>Не то.
Почему?
C>Оно работает на заранее перечисленных типах. Это не перегрузка.
Ну да. Тем не менее, люди вот так извращаются. И запросто может оказаться, что кто-то "переопределил" таким образом, ты включаешь какой-то файл и поведение меняется.
C>Ну вот С++ весь такой. И D тоже приближается к нему.
Все "развивающиеся" языки приближаются.
Конечно, можно делать это более или менее удачно. В С++ корявых мест хватает, но то, к чему ты придрался — вообще ерунда и проблем не вызывает.
Кстати, я не занимаюсь доказательством преимуществ D, если что.
C>Стандартная библиотека, если она не в виде компиляторной магии, — это не проблема.
Если "компиляторная магия" позволяет сделать что-то удобнее/быстрее, то почему бы и нет.
Да и некоторые фичи являются основными для языка. Скажем, невозможность объявить функцию без подключения (пусть и стандартной) библиотеки выглядит дурацки. Если вдруг забыл, то мы говорили о том хорошо ли что-то "встраивать в язык".
C>И не надо.
Надо или нет — не важно. Факт, что далеко не всё ты сможешь сделать.
Re[29]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
_>Безусловно второй вариант красивее. Однако это единственное их отличие. Т.е. если у нас есть реализация для then, то это полностью решает твою задачу. А все твои претензии сводятся уже не к возможности решения, а к красоте, т.е. по сути синтаксическому сахару.
начиная с ассемблера всё есть сахар
_>А вот на D, благодаря наличию в нём перегрузки оператора вызова функции-члена, можно в одну строчку реализовать синтаксический сахар в точности, как ты хочешь.
Напомню, мы подключаем внешнюю либу, у ней как глобальные так и все остальные функции сделаны на колбеках.
У кого ты собираешься перегружать оператор вызова?
Re[30]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Ikemefula, Вы писали:
I>Напомню, мы подключаем внешнюю либу, у ней как глобальные так и все остальные функции сделаны на колбеках.
I>У кого ты собираешься перегружать оператор вызова?
У future естественно. Так что у него можно будет вызвать произвольную функцию член (и оператор соответственно форвардит этот вызов к внутреннему типу, через then). Т.е. благодаря этой фичи языка D у класса future<XR> будет иметься метод y, который будет возвращать future<YR> (делая при этом внутри вызов настоящего y через then). И всё это ровно в одну строчку и для всех типов сразу.
Но опять же, это всё просто синтаксический сахар, а работающий вариант мы имеем и на C++, просто он выглядит чуть длиннее.
Re[31]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
I>>У кого ты собираешься перегружать оператор вызова?
_>У future естественно. Так что у него можно будет вызвать произвольную функцию член (и оператор соответственно форвардит этот вызов к внутреннему типу, через then). Т.е. благодаря этой фичи языка D у класса future<XR> будет иметься метод y, который будет возвращать future<YR> (делая при этом внутри вызов настоящего y через then). И всё это ровно в одну строчку и для всех типов сразу.
У тебя решение, как сделать второй и последующие вызовы. А как сделать первый ?
т.е. вместо x(success, error) надо x() и он должен вернуть тот же тип, что приходит в success колбеке.
Re[32]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Ikemefula, Вы писали:
I>У тебя решение, как сделать второй и последующие вызовы. А как сделать первый ?
Ну да. Так вроде мы только на проблеме организации цепочек вложенных асинхронных вызовов и остановились, т.к. с просто вызовами давно всё обсудили. И кстати надо признать, что на C++ организовать цепочку с точно такими фичами, как ты хотел, не выходит. Только несколько более громоздкая выходит на плюсах, хотя по смыслу естественно всё тоже самое. А вот на D уже всё в точности как ты хочешь.
I>т.е. вместо x(success, error) надо x() и он должен вернуть тот же тип, что приходит в success колбеке.
Ну во-первых x() будет возвращать не тот тип, что приходит в success, а future<> от него.
. Применительно конкретно к нашему случаю, внутри x() будет просто один вызов x(success, error) с лямбдами, в которых будет promise.set_value, ну и соответственно в конце return promise.get_future(). Кстати, этот код вполне универсальный (с точностью до определения нашего асинхронного апи), так что его можно оформить в один шаблон, который будет подходит сразу под все подобные функции (x, y, z).
Re[33]: Язык D - действительно красота и эффективность в одном ф
. Применительно конкретно к нашему случаю, внутри x() будет просто один вызов x(success, error) с лямбдами, в которых будет promise.set_value, ну и соответственно в конце return promise.get_future(). Кстати, этот код вполне универсальный (с точностью до определения нашего асинхронного апи), так что его можно оформить в один шаблон, который будет подходит сразу под все подобные функции (x, y, z).
Применительно к нашему случаю — весь код JS будет в либе. Не нужно даже генерировать код. То есть, вообще. Более того, и руками не нужно будет помогать. Так что в целом смотрится очень смешно.
"Кстати, в том же JS я что-то не помню реализации чего-то подобного..."
Re[34]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Ikemefula, Вы писали:
I>Применительно к нашему случаю — весь код JS будет в либе. Не нужно даже генерировать код. То есть, вообще. Более того, и руками не нужно будет помогать. Так что в целом смотрится очень смешно.
А что тебе мешает закинуть весь этот код в либу в D? И зачем где-то помогать руками? )
Re[35]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, alex_public, Вы писали:
I>>Применительно к нашему случаю — весь код JS будет в либе. Не нужно даже генерировать код. То есть, вообще. Более того, и руками не нужно будет помогать. Так что в целом смотрится очень смешно.
_>А что тебе мешает закинуть весь этот код в либу в D? И зачем где-то помогать руками? )
Ты же ни решения, ни набросков не показал
Re[36]: Язык D - действительно красота и эффективность в одном ф
Здравствуйте, Ikemefula, Вы писали:
I>Ты же ни решения, ни набросков не показал
Ээээ что? )Я тебе показал как преобразовать коллбэк в асинхронный вызов (и на C++ и на D одинаково) и как организовать цепочку таких вызовов (красиво на D и чуть пострашнее на C++). Причём всё это в виде шаблонов, так что пишется один раз и закидывается в библиотеку. Чего тебе ещё не хватает то? )