LINUX.ORG.RU

а вот так можно ?

Нет конечно. Типы определяются при компиляции.

Можно так:

std::variant<std::string, int> workingFunction(int x)
{
  if(x==42) return "Мужик, это был смысл жизни, вселенной и всего такого!";
  return x*2;
}

Тогда можно запрашивать x у пользователя.

monk ★★★★★ ()
Ответ на: комментарий от monk
getType : (isInt : Bool) -> Type
getType False = String
getType True = Int

workingFunction : (x: Int) -> getType (x /= 42)
workingFunction 42 = "Мужик, это был смысл жизни, вселенной и всего такого!"
workingFunction x = x*2

main : IO ()
main = do putStr $ workingFunction 42
          putStr $ "Квадрат 122 равен " ++ (show $ workingFunction 122)

String ++ Int ? Так можно?

нет, это я описался, show нужен

типобезопасный printf А если в него шаблон из пользовательского ввода грузить, то что будет?

Я когда года два назад увидел код, тоже этим вопросом задался. Но вопрос на вскидку - как ты будешь параметры туда передавать если ввод пользовательский? Т.е. там ведь переменное число параметров идёт после шаблона…

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от monk

Да, вот так очень похоже на то как должно быть.

Как это вывести в cout? Стработает просто cout << workingFunction(42)? Оно ведь автоматически каститься когда выводится кажется.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от AndreyKl

Т.е. там ведь переменное число параметров идёт после шаблона…

Берём типовой пример применения gettext. Типы параметров шаблона разные, а сам шаблон зависит от переменной окружения.

monk ★★★★★ ()
Ответ на: комментарий от AndreyKl

Как это вывести в cout? Стработает просто cout << workingFunction(42)? Оно ведь автоматически каститься когда выводится кажется.

Нет. Или get с явным указанием типа, либо std::visit.

struct make_string_functor {
  std::string operator()(const std::string &x) const { return x; }
  std::string operator()(int x) const { return std::to_string(x); }
};


std::cout << std::visit(make_string_functor(), workingFunction(42)) << "\n";
monk ★★★★★ ()
Ответ на: комментарий от monk

Берём типовой пример применения gettext. Типы параметров шаблона разные, а сам шаблон зависит от переменной окружения.

Если шаблон дан в тексте программы (ну т.е. что то вроде
printf(_("Hello, %name"), name)), то напрашивается вариант как то доказать что gettext (и ngettext) не испортят шаблон. Т.е. он будет изоморфен оригиральному в смысле подставленных переменных.
Либо как то расширить printf чтобы она могла игнорировать часть параметров (т.е. если они даны в строке командной, но не даны в шаблоне, то пофиг). Но это уже становится не совсем printf, кажется.

Если же вообще могут быть любые модификации шаблона или шаблоны не видно в коде, то есть возможность какую то функцию написать используя идрисовскую рефлексию, которая в компил тайме прочитает шаблоны (вероятно из отдельных файлов) и проверит что параметры подходят.

Естественно гарантия распространяется только на проверенные шаблоны, если их кто то изменит после компиляции, то как бы и всё. Но это, кажется, очевидно.

Если вообще любые шаблоны которые пользователь вводит в рантайме, то надо писать обычную проверку в рантайме, можно ли что-то ещё придумать я не знаю.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 3)
Ответ на: комментарий от AndreyKl

то напрашивается вариант как то доказать что gettext (и ngettext) не испортят шаблон

С учётом того, что они при выполнении читают внешний файл, по-моему, нереально.

Если вообще любые шаблоны которые пользователь вводит в рантайме, то надо писать обычную проверку в рантайме, можно ли что-то ещё придумать я не знаю.

Поэтому я и пишу, что printf с типобезопасностью малоосмысленен.

monk ★★★★★ ()
Ответ на: комментарий от monk

С учётом того, что они при выполнении читают внешний файл, по-моему, нереально.

Да, я написал, потом тоже решил, что если задуматься - невозможно. Ведь в файле может быть любой шаблон, в том числе и неправильный. Это ведь не преобразование по какому то правилу, а произвольная строка. Ничего там не докажешь.

Но можно читать шаблон в компил тайме.

Поэтому я и пишу, что printf с типобезопасностью малоосмысленен.

1) Я бы сказал что куча ошибок переполнения емнип была связана с неверным использованием printf. printf вполне используется, даже без gettext.

2) Мне кажется что (гипотетическая) возможность проверки шаблона в компил тайме вместе с параметрами его функции обработчика - вполне себе заслуживающая внимания возможность. Помню кучу времени потратил на тестирование шаблонов писем и всё равно были с ошибками. Может быть удастся сделать это получше. Правда «printf» всё таки нужен для этого дела более безопасный в любом случае. Правда если параметры в базе лежат.. да, тут всё сложно. Тем не менее возможность чтения файла в компилтайме кажется хорошей.

3) Но и дело не только в printf. Это в первую очередь интересный пример того, для чего обычно надо подшаманивать компилятор и что «обычному» программисту на cи/си++ и даже haskell вряд ли доступно. Тут видно что возможности значительно шире.

AndreyKl ★★★★★ ()
Ответ на: комментарий от AndreyKl

Мне кажется что (гипотетическая) возможность проверки шаблона в компил тайме вместе с параметрами его функции обработчика - вполне себе заслуживающая внимания возможность.

В gcc она есть.

Это в первую очередь интересный пример того, для чего обычно надо подшаманивать компилятор

В C++ есть tinyformat, который позволяет избежать ошибок переполнения. И есть boost::format, который является нормальной заменой printf.

А для «подшаманивать компилятор» лучше сразу полноценные макросы.

monk ★★★★★ ()
Ответ на: комментарий от monk

В gcc она есть.

Можно ли написать проверку того что шаблон соотвествует параметрам аргументов printf в коде (теоретически)? Без написания собственного парсера си или его части, конечно.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от AndreyKl

printf не нужен в С++, все пользуются fmt( или std::format, который в течение двух недель будет в MSVC 2019)

и там все проверки есть, и это сторонняя либа то есть любой может написать такую же.

https://gcc.godbolt.org/z/M7o5MdzT3

https://gcc.godbolt.org/z/Yf3ebx9TM

fsb4000 ★★★★★ ()
Ответ на: комментарий от monk

И есть boost::format, который является нормальной заменой printf.

В 20м стандарте уже в stl.

https://github.com/c42f/tinyformat

Есть ещё https://github.com/fmtlib/fmt, тоже header-only (опциально).

thunar ★★★★★ ()
Последнее исправление: thunar (всего исправлений: 4)
Ответ на: комментарий от monk

Я не совсем понял ответ. Речь шла о шаблоне находящемся во внешнем файле. Т.е. есть внешний файл a.tpl, скажем. Есть мой файл f.cpp.

В a.tpl хранятся строки вида Hello, my dear %s. You owe me %f.3 rubles.

А в f.cpp есть printf вида

t = readtemplate ("a.tpl")
printf(t, name, money)

так вот вопрос, можно ли проверить (гипотетически) стандартными средствами с++ что строка в a.tpl соотвествует шаблону printf из файла f.cpp?

Я бегло проглядел документацию к tinyformat, но на вскидку не увидел.

Не то что бы меня интересует вопрос именно с форматом, но фича как мне кажется очень интересная, в общем. Например, в play framework есть роутинг ( https://www.playframework.com/documentation/2.8.x/ScalaRouting ). Вкратце, отдельный файлик в котором прописаны строки условно вида

GET / Controllers.MainCtrl.index()
GET /($arg=[d+]) Controllers.MainCtrl.ArticleByNum($arg)

Я не знаю как это у них на скале сделано, но на сколько я понимаю это можно сделать стандартными средствами идрис и проверять во время компиляции.

Т.е. будет строгая типизация и проверка во время компиляции что все контроллеры на месте и параметры и регулярки верные и (вероятно) соотвествуют адресам.

Т.е. речь идёт о вот подобной возможности. Я не совсем понял как там tinyformat поможет.

PS. Прошу прощения что выпал из дискуссии, времени не хватает.

AndreyKl ★★★★★ ()
Ответ на: комментарий от AndreyKl

так вот вопрос, можно ли проверить (гипотетически) стандартными средствами с++ что строка в a.tpl соотвествует шаблону printf из файла f.cpp?

tinyformat должно будет исключение кинуть, если формат неверный

monk ★★★★★ ()
Ответ на: комментарий от monk

Я не прав: By default, tinyformat calls assert() if it encounters an error in the format string or number of arguments. This behaviour can be changed (for example, to throw an exception) by defining the TINYFORMAT_ERROR macro before including tinyformat.h, or editing the config section of the header.

То есть ошибки обрабатываются через assert()

monk ★★★★★ ()
Ответ на: комментарий от monk

Я говорю о компилтайме. У тебя о рантайме ведь речь?

Я говорю о возможности языка написать средствами языка парсер, который в компилтайме проверит соотвествие шаблона из файла некоторым правилам, заданным в исходном коде.

И это не хак компилятора, а более-менее обычный код (на идрисе это зовётся рефлексией насыщателя (?? что ли.. не знаю как по русски elaboration reflection) http://docs.idris-lang.org/en/v1.1.1/reference/elaborator-reflection.html)

Правда этот код сам не идрис.. т.е. он не типизируется зависимыми типами, это как бы скриптовой подъязык, вроде тактик в коке. Если я верно помню это.

...

Т.е. это сам идрис, но это отдельная монада. Т.е. там можно писать как в хаскеле что угодно внутри монады и это не особо проверишь типами, т.е. там проверка довольно слабая.

Но эта слабая проверка относится к коду выполняемому в компил-тайме.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 8)
Ответ на: комментарий от AndreyKl

Если твоя строка известна на этапе компиляции (т.е. ты не формируешь ее динамически в рантайме), то на ней можно вызвать constexpr функцию, которая отработает во время компиляции. Там можешь распарить ее и проверить на соответствие каким-то критериям и в случае чего вывалить static_assert — компайл-тайм assert. Доступа к AST программы у тебя не будет, но типы аргументов получить можно.

filosofia ()
Ответ на: комментарий от AndreyKl

Я говорю о компилтайме.

readtemplate («a.tpl»)

Как можно в компилтайме хоть что-то сказать о том, какое содержимое будет у файла «a.tpl» в рантайме? Или это не файл, а ссылка на константу в программе?

monk ★★★★★ ()
Ответ на: комментарий от AndreyKl

который в компилтайме проверит соотвествие шаблона из файла некоторым правилам

Тогда ты обязан содержимое этого файла вкомпилировать в бинарник. Или требовать от пользователя его не менять (но тогда почему не вкомпилровать в бинарник?)

monk ★★★★★ ()
Ответ на: комментарий от monk

Как можно в компилтайме хоть что-то сказать о том, какое содержимое будет у файла «a.tpl» в рантайме? Или это не файл, а ссылка на константу в программе?

Тогда ты обязан содержимое этого файла вкомпилировать в бинарник.

Да, в целом так. Я говорил что пример с printf не слишком отражает суть проблемы и привел выше пример где это осмысленно. Хотя, наверное бывает и с printf осмысленно.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от filosofia

Если твоя строка известна на этапе компиляции (т.е. ты не формируешь ее динамически в рантайме), то на ней можно вызвать constexpr функцию, которая отработает во время компиляции. Там можешь распарить ее и проверить на соответствие каким-то критериям и в случае чего вывалить static_assert — компайл-тайм assert. Доступа к AST программы у тебя не будет, но типы аргументов получить можно.

Спасибо за дополнение/пояснение. В целом понятно.

AndreyKl ★★★★★ ()