Latest tip build error

On both Windows and OSX, in Rectangle class (and anywhere i used the StringArray addTokens method)

toks.addTokens (stringVersion.trim(), T(",; \t\r\n"), 0);

error: conversion from 'int' to 'const juce::String' is ambigous

i had to replace 0 with String::empty everywhere to build.

Sorry, I thought I’d updated all of those. Thanks, I’ll sort it out.

Also String::formatted is gone, will it be back ? or will there be something similar ?

No, I deliberately got rid of that. Any self-respecting c++ guru will tell you to avoid printf, and use more modern c++ techniques like operator<< instead.

(Of course, you can still call sprintf yourself and turn it into a String, but I want the library to be free of old-fashioned stuff like that…)

No, I deliberately got rid of that. Any self-respecting c++ guru will tell you to avoid printf, and use more modern c++ techniques like operator<< instead.

(Of course, you can still call sprintf yourself and turn it into a String, but I want the library to be free of old-fashioned stuff like that…)[/quote]
Is this a joke ?
Jules, you’re shooting yourself in the foot here.

operator << is the most horrible interface for string formatting that can be (even Herb Slutter told so). There is a lot of issues, but I’ll just list the major one:

  1. Not internationalization capable.
    For example, I want to print “I have 3 blue pigs”, stl code will require
str << TRANS("I have ") << pigCount << color << TRANS("pigs");

Then you realize you need to write the software for french, the sentence becomes “J’ai 3 cochons bleus”, which would need such code:

str << TRANS("I have ") << pigCount << TRANS("pigs") << color;

This means that you must write different code for different language!
(BTW, with formatted method, you’d have written TRANS(“I have %d %s pigs”) which would have been “J’ai %d cochons %s” in the french translation file).

  1. State dependent formatting.
func1(string & str)
str << std::hex; 
func2(string & str)
str << 32; // Go figure why when calling func2 you'll get "20" in the string instead of the programmer expected "32";
// Also, the floating point conversion code depends on what the FPU mode is at the time of conversion
// Also, your code likely don't support all the floating point formatting option that sprintf does (like %e %g %.3f %06.%2lf) as it's not specified in C++ standard
  1. It’s a pain to write, and as such, a pain to maintain.
    Ok, this is equivalent : %d and << (int)
    But go format this: %08x ?
    The iostream code becomes:
str << std::hex << std::setfill('0') << std::setw(8) << x << std::dec;

Please remark that the code below doesn’t restore the default width to what it was previously, so the next code will print integer as “00023456” (is it hex ? is it integer ?) - so you’re back to issue #2

While you’re reading all the C++ books, please read Alexandrescu critics about this, and his solution in

Please, please don’t remove formatted or I’ll have to switch all the code we have written to our own text formatting code.
This is really what I initially liked in Juce that it picked the best of C, C++ and Java and threw away the horrible things in C++ (like operator << and all the stl horrors with stupid 20 parameters template code).

Really, if you transform Juce to be another stl-ish code, I guess I’ll have to just use Qt, but for me it means a real deception.

i’ll back up X-Ryl669 in this.

Also it’s a pain in the ass to write hex/bin/dec formatted data, and i need a lot of that when coping with MIDI stuff. Also the length and spacing modifiers in the sprintf() style calls are very useful in console based apps. So if it’s possible i’d love to see that method back.

Well, I’ve always hated printf, and mixing it with String objects just provides too many exciting opportunities for unsafe code. Although << isn’t perfect, whenever I’ve rewritten printfs to use it, I’ve found the result a lot more pleasing.

…and then when the translator accidentally swaps the order of the %d and the %s, you get an almost impossible-to-find corrupted memory bug. The smart programmer would write TRANS(“I have %PIGS pigs”).replace (“%PIGS”, String (numPigs)).

True, printf is good for things like “%08X”, but I was planning to come up with a bunch of new number formatters so you could write things like Hex::toString, Decimal::toString etc (with lots of formatting options), to do all the same things in a more functional way.

But FFS, in less time than it must have taken to type that almighty rant, you could have written a trivial global function (maybe 5 or 6 lines of code?) that does exactly the same thing as String::formatted, and then globally searched/replaced “String::formatted” with the function name…

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 ( ).
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).

Off topic, I didn’t knew about FFS meaning, it’s nice. Who’s almighty ?

Oh my god! The ranting!

I did get it. But you were suggesting breaking the golden rule of safe printfs, which is to only ever use a string literal as the format string - that’s the sort of coding that makes me even more determined to get rid of printfs and save people from themselves!

Yes, I’ve seen the typesafe printf stuff before, and I agree that it’s a neat idea - maybe I’ll implement something like that, it might be an interesting programming challenge.

I think “FFS” is a fair thing to say when someone has a ridiculous over-reaction to something that’s actually pretty trivial! I removed a method call, and you could replace it with your own equivalent version in 2 minutes if you’re determined to do things that way. Not a big deal. No need to throw a tantrum!

I must admit, I really don’t understand the need to remove the facility from String; it is quite a common thing to do, and while it may not be what you’d recommend, is there actually any gain from removing a basic standard feature from a ‘fully featured’ string class? Maybe I’m missing something.

Apart from anything else, I’m in the process of trying to convince my seniors at work that juce is a good viable library for our tools. We make games on all platforms, and sprintf is an essential function in our day-to-day coding, they would be appalled to learn that it WAS in the string class, but was taken out; regardless of the reasoning behind it, it will be viewed as an act of code practise dictatorship (many have strong views against rigid OOP conformity, which kinda comes with the territory when you work on the sort of software/platforms that we do). I’m perhaps a little more flexible, and like a spot of elegance, but it does strike me as an unnecessary culling of a legacy feature.

I’m amazed by all this support for it! I’ve always hated the function, I wish I’d never put it in there in the first place!

:slight_smile: i’m not sure i’d say that i’m personally supporting it - i rarely find myself with the need for it when i’m coding jucely. The people I want to convince, however, would see its removal as a dark shadow on a library they’re already unsure of. OOP for OOP’s sake is a sin in their eyes :slight_smile:

While elegance is better, good practice paramount, and well-structured design key, what purpose is there to strip standard legacy functionality out? I’m struggling to think of a benefit - if it’s already written, proven and tested, what gain is there? It’s not like anyone is going to accidentally use it - it’s a very specific tool, but it is one that is effectively standard (and powerful). Noone is in any danger with it being there, but its absence will certainly be noticed.

Like I said, I’m personally indifferent about it, but I just don’t understand.

Sorry for starting this discussion. Like Jules said i’ll add this function myself no problem. I was just curious why was it gone, i came form ANSI C so sprintf vsprintf and others were my friends and i got used to them. I really don’t like the << operator it’s completly unreadable to me and it’s just unusable for me when writing complex expressions. But all i wanted to know was this planned or just something Jules missed, now i know i’ll live with that.

One thing i’d like to add, i’m a Slackware Linux user for years (since version 4.0) and what i liked about it, is that it was always a one-man idea, and that’s why it was consistent, the same is with JUCE, so anything Jules says i’ll accept.

ah, slave-like obedience, that’s what I like!

What I expected was that people would take it as a kick-up-the-butt to move their old C-style code to a safer style, and that they’d think “ah yes, I’d been meaning to get rid of my old printfs anyway - this is a good incentive to do so…” I didn’t expect people to be unashamedly still using them!

If people feel really strongly, I don’t mind putting it back. But if I did, I’d want to try to prevent people doing two particularly stupid things with it, which are:

  • supplying a format string that isn’t a literal constant
  • passing a String as one of the vararg parameters
    It’s probably possibly to make the compiler emit a warning about the first (they should already warn you if you do that with a normal printf), but I’m not sure how you’d do the second… Any ideas?

If I send you my typesafe printf-like code, would you use it ?
I’m using () operator for this, this gives this code:

Debug(TRANS("I have $1d $2s pigs"))(pigCount)(pigColour);

This is using the same syntax as printf for text formatting (that is 08X is hexa), but I use $pos for the argument position. operator() use template parameter which in turns call Convert<T, Format>::formatString(Format formatToUse, T parameter).
(It’s very like Alexandrescu, and boost implementation).

Well, can’t promise I’ll use it, but I’ll certainly take a look if you want…

For what it’s worth, I’ve got to agree with the sense of everybody else about printf. It may violate some religious principles that Jules seems to have, but it’s damned useful. Not only that, but the capricious removal of this and other functions without at least one version where it’s listed in the documentation as deprecated, means that we’ve got to keep scrambling after Jules, making continual changes just to keep the same code working. On top of all that, if we’ve got stuff in the field to support, we have to gradually fill up our code with conditional compilation.

I understand that many attributes of Juce are ad-hoc, and I also deeply appreciate the tremendous effort that goes into it with minimal remuneration. At the same time, there should be a certain inviolate nature to an API. Add new stuff. Fix stuff. But give it a rev or two before removing something.

Fair enough. So I take it the general consensus is that it should go back in, then?

That would be great. I’m discovering some other functions that may be issues, but I’ll try to work around them first before I complain. In a larger sense, I hope we can find a way that allows you to follow a trajectory of continuous improvement while still giving us a chance to update our code with a little less sense of panic.