You didn’t get it. It’s not about the number of pigs, it’s about the sentence structure itself.
English people tends to think that words in any english sentence will match the same order in any other language, that’s why you get so funny quotes from “internationalized” software (search for “sur la mouche” if you understand french you’ll get a very good time).
The TRANS(“make my own ‘printf-like’ statement”).replace().replace()… and so on is like re-inventing the wheel, with :
- no standard replacement string (so, dev1 will use %PIGS while dev2 will use %COUNT etc… => unmaintainable when you have a large dev team)
- its longer to type than “<< operator” or printf (you must have as much replace as you have items, and in addition you must provide a conversion code to string)
- it’s fully inefficient, as you’ll parse the same string multiple times => O(N * M)
- What if the replacement gives a key to the next replacement like String(“I have %NB %CLR pigs”).replace(“%NB”, String(“a %CLR”)).replace(“%CLR”, “blue”) ?
There is nothing that prevent you from writing typesafe printf code (I’ve done this in the past for a previous company I’ve worked for)
The link I’ve posted in the previous post is exactly about this. C# did this, Java did this too, boost have it too ( http://www.boost.org/doc/libs/1_42_0/libs/format/index.html ).
However this adds to the learning curve of your library (boost at least supports printf like statement in type safe way).
What you proposed is called custom placeholder, but printf at least is standard.
printf is not this “unsafe” beast you think it is, it is, at least, a standard of text formatting.
It’s good for so many things, that you’ll go crazy about this if you try to reimplement each possible option as a formater object.
It’s a mini language by itself, you can even have meta programming with printf.
For example, you want always 64-wide string, just use 4 chars: “%64s” (4 bytes), you can repeat the same argument multiple time “%1$d %1$d”, etc…
This is wrong, and this is why it’s better to use printf instead of make-your-own replace code.
All new compiler checks type safety in the printf-like strings. So this call will emit a warning in GCC
printf("%s", 3); // warning: format ‘%s’ expects type ‘const char*’, but argument 2 has type ‘int’
Even with runtime loaded string, you can assert the string match the argument types with RTTI.
Also, printf support “%pos$d” parameter meaning that you can keep the same code whatever the language used in the format string:
ie: printf(TRANS(“I have %1$d %2$s pigs”), pigCount, pigColor) will work even if TRANS returns “Izçh %2$s %1$d strañtchë” (notice swapped type in the formatting)
You agree with me then. What you’re saying is that your current code based on << is useless for any serious user based visual string output (which is, probably 90% of strings in an UI application),
as you have to re-invent the wheel for internationalization.
So “<< code” might be more “pleasing” for the Jucer writing pure-english based project solution file and source code, but really, as soon as you’re doing something serious with i18n, bam, you’re stuck replacing all your “<< code” to basic printf-like code (with replace, whatever).
I agree that printf(userInputText, 0) is a loaded gun in front of your own head, but so is “std::cin << userInputText” (as it can be NULL).
Please don’t make the same mistakes as C++ “gurus” did so many years ago, and later tried to fix with boost…
Please at least provide a facility not based on intermixing code with presentation (like the iostream mess), something like:
String::print(TRANS("I have {0} {1} pigs pointing at {08h2}")) << pigCount << pigColor << &pig; // Or whatever operator you want here for type safety, can be % or | or even ()
^ Presentation ^
// And not:
String::print(TRANS("I have {0} {1} pigs pointing at {h2}")).replace("{0}", String(pigCount)).replace("{1}", String(pigColor)).replace("{h2}", Hex(&pig)::toString())
^ Presentation ^ ^ Presentation too ^
// Or even worse:
str << TRANS("I have ")<< picCount << pigColor << " pigs pointing at " << std::hex << (size_t)(&pig);
^ Presentation everywhere (untranslatable) ^
It’s one of the first think I do with a Jucer generated code : replace T() to TRANS() (should be the default BTW, as you must think i18n at design time).