7

In cases where the full text of the format string is static and known at compile time, shouldn't a missing format string parameter be a compile-time error or, at the very least, warning?

ReSharper catches this, but it's just an underlined squiggle. I was under the impression that this would trigger a general compile-time error:

string x = string.Format("soeuotnh {0}");

Is there any way to trigger a warning on this kind of error without having to run my code through FxCop or something? Even C/C++ compilers will trigger an warning/error for such a blatantly clear bug (though they generally won't check type-safety).

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • 3
    The compiler doesn't parse your format string, so how is it supposed to know that you're missing a parameter? – M.Babcock Apr 17 '12 at 16:31
  • 4
    `String.Format` is not part of the C# programming language. Why would the compiler care about it? – John Saunders Apr 17 '12 at 16:32
  • yep, not a compiler job to do that - 'Format' is just a custom method really as far as compiler goes – NSGaga-mostly-inactive Apr 17 '12 at 16:32
  • 2
    I'm pretty sure the C/C++ compiler won't parse your `printf` format either... – M.Babcock Apr 17 '12 at 16:33
  • C# compiler is very limited compared to most C/C++ ones. – Agent_L Apr 17 '12 at 16:33
  • @Agent_L - Be careful when talking about the C# compiler around here. Eric Lippert might catch you and slap you with a fish. – M.Babcock Apr 17 '12 at 16:41
  • @JohnSaunders, NSGaga: A compiler isn't *limited* to the spec. It can go beyond that to ensure quality. That's why they're called warnings. M.Babcock Have you ever coded C? C compilers do catch it even though "printf" isn't part of the spec either (and without -Wall, even!): https://gist.github.com/2407405 – Mahmoud Al-Qudsi Apr 17 '12 at 16:45
  • @M.Babcock: Some compilers will warn about type compatibility issues in calls to `printf` (VS2010 does). It doesn't catch everything, but that tells me it is in fact parsing my format string. – Ed S. Apr 17 '12 at 16:47
  • @MahmoudAl-Qudsi: If my compiler starts doing things that are not in the spec, then I want to send it back and ask for a real compiler. – John Saunders Apr 17 '12 at 16:49
  • Wow. I thought I did well in my compilers course 35 years ago, and I thought I had been using them for about the same time. I could have _sworn_ compilers optimize within the limits of what the language tells them they can. – John Saunders Apr 17 '12 at 16:55
  • Why not just buy ReSharper and be done with? It will tell you about this sort of problem and much more. That's because _it's not the compiler_. – John Saunders Apr 17 '12 at 16:57
  • @ M.Babcock yeah, my bad. I remembered some warnings about printf, but they had to be about passing non-POD object. I'd let myself to be slapped in exchange for a question about templates or at least macros. So I'm still standing to my words : ) – Agent_L Apr 17 '12 at 16:58
  • @JohnSaunders read my post. I do have ReSharper. – Mahmoud Al-Qudsi Apr 17 '12 at 16:59
  • You said ReSharper does it, you didn't say you _have_ it. Just increase the severity from warnig to error, and use solution-wide error processing, and keep an eye on the little red circle. You want no little red circle. – John Saunders Apr 17 '12 at 17:00
  • 1
    Guys, obviously any answer aside from "You are 100% correct" is wrong. Just post that for a quick 15 points. – Ed S. Apr 17 '12 at 17:02
  • Which question do you actually want answered here? _Shouldn't missing format string parameters be a compile-time error?_ or _Is there any way to trigger a warning on this kind of error without having to run my code through FxCop or something?_. The former is actually borderline not constructive. – M.Babcock Apr 17 '12 at 17:11
  • I confess that for this reason I prefer not using `String.Format` and I compose strings with `+`. It is not nice, but I prefer not to have runtime errors. – piertoni Nov 20 '20 at 08:31

7 Answers7

2

It could be a warning, but should it be? Well, that's up to the compiler team I suppose, it's not like String.Format is a part of the C# language.

This isn't C; you're not invoking undefined behavior or anything, the method can simply deal with the missing parameter and the assumption is (I assume...) that you will catch it pretty quickly when it throws an exception. There's nothing "dangerous" about it, it's just a logic error.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
2

I don't think there is any way other than what you mentioned for detecting this condition automatically. As to why this happens, the Format method is matching against the (String, params Object[]) overload, which the parameters are defined in the documentation as this:

public static string Format(
    string format,
    params Object[] args
)

format Type: System.String
A composite format string (see Remarks).

args Type: System.Object[] An object array that contains zero or more objects to format.

Since the params defines a variable number of arguments (including zero arguments), that is why there is no compile-time exception thrown.

Edit:

Since there is a valid overload for the compiler to select, then you won't get a compile-time error. So this ceases to become a compiler issue, and your best bet is to use Resharper, which is a code quality tool, to detect this condition.

mgnoonan
  • 7,060
  • 5
  • 24
  • 27
  • There is of course "A way", it would be a feature that would be added to the compiler. IMO it just isn't worth it, and it's kind of a weird thing to build in a feature for a method call that isn't part of the language, so it doesn't exist. – Ed S. Apr 17 '12 at 16:38
  • And it does throw an exception BTW. – Ed S. Apr 17 '12 at 16:41
  • Well, yes, but assuming you are not a part of the compiler team, I don't have any additional suggestions. In any case the documentation already defines this as a legal statement, so really this would at best be defined as a compiler warning. – mgnoonan Apr 17 '12 at 16:41
  • Which is my question - why not a warning? – Mahmoud Al-Qudsi Apr 17 '12 at 16:42
  • I didn't try it, but yes it might throw a run-time (as opposed to compile time) exception). Weird though, the documentation specifically says "zero or more objects". – mgnoonan Apr 17 '12 at 16:43
  • @MahmoudAl-Qudsi A question only MS can answer. Perhaps you should put in a feature request. – mgnoonan Apr 17 '12 at 16:44
  • @MahmoudAl-Qudsi: Because A) it isn't part of the language and B) it isn't illegal as far as the language is concerned. Why should C# *the language* know anything about `String.Format`? – Ed S. Apr 17 '12 at 16:44
  • @EdS. for the 10th time, the compiler's job isn't just to follow the spec, it's to do anything it can to help you create better code and binaries. Optimizations aren't part of the spec, why does your compiler do them? – Mahmoud Al-Qudsi Apr 17 '12 at 16:49
  • @MahmoudAl-Qudsi: Actually it is the compiler's *only* job to follow the spec. Anything else is icing on the cake. Not sure where you got that idea. You're saying that a quality of life type feature should be required, which is just silly. Besides, it only serves on use case. If my format string is variable then it can't do anything about it. – Ed S. Apr 17 '12 at 16:58
0

Some C compilers will parse format strings because having format strings that don't match the parameters can cause serious crashing bugs -- or even worse, security bugs. In C#, though, you just get an exception at the call site, so it's not critical.

The compiler could do it, but that would require code to recognize string.Format as a special case, and (even worse) would need somebody to write a format string parser in the C# compiler. All so that it can warn you about code that will crash every time it's executed.

The big problem with this is that many people compile with all warnings on and warnings as errors, meaning that adding this warning will break their build. Anybody with some bad format string in a dark corner of their code where it's never executed will suddenly be unable to build their product. These people will complain.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • 2
    Sorry, but that's the most pitiful excuse I've ever heard. That's *exactly* the problem: when it's in "some dark corner of your code" you won't (likely) catch it in testing, and that's ESPECIALLY why the compiler should throw an error. If you had a `int x = 7 / 0` in a dark corner of your code, it's a compile-time error. And you SHOULDN'T be able to ignore runtime exceptions just because they're tucked away somewhere! – Mahmoud Al-Qudsi Apr 17 '12 at 16:51
  • 1
    @MahmoudAl-Qudsi: Why are format strings special? There are whole classes of runtime errors that can be caught at compiler time (e.g. passing null to methods documented to not accept null). By your reasoning, the compiler should have special code to look for all of those, too -- and those don't require a special mini-language parser. – Gabe Apr 17 '12 at 17:16
0

As has already been said, this isn't something the compiler does or should worry about.

How would you expect the compiler to behave when doing something like:

string format = "{0}";
List<string> parms = new List<string> { "Hello" };

if (DateTime.Now.Second % 2 == 0)
{
    format += " {1}";
    parms.Add("World");
}

Console.WriteLine(format, parms.ToArray());
M.Babcock
  • 18,753
  • 6
  • 54
  • 84
  • I don't. But I do expect it to try. C/C++ will make a best effort to analyze your string format specifiers, and it's far harder for them than it is for the C# compiler. – Mahmoud Al-Qudsi Apr 17 '12 at 16:52
  • 1
    @MahmoudAl-Qudsi: Except in C you are invoking UB, in C# the behavior is perfectly well defined. It's more dangerous in C, so it is worth it. – Ed S. Apr 17 '12 at 16:57
0

Resharper shows warning for this case: "Non-existing argument in formatting string".

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
-1

The "format" parameter of the method is not constant. Everything that is not constant can not be checked at compile-time.

It can be composed at run-time via various methods, it can even be user-input... (The horror!)

That's why it is not a compile-time error.

Edit: OK, In the case that it is a constant expression it could be analyzed and a warning could be generated. But here is the answer from Eric Lipert on a different question a bit aplicable: There's a bar of benefit over cost.

Whether this is a real benefit that is worth spending the special case scenarios for String.Format (and possibly other string format functions) is... a tough call.

Community
  • 1
  • 1
Jeroen Landheer
  • 9,160
  • 2
  • 36
  • 43
  • Well, many times it is constant, in which case it could catch it. This isn't a technical problem, it's one of separation of concerns and utility. Is this really a big enough problem to justify adding it to the *compiler* given that `String.Format` isn't even a part of the language? It's a decision that was made. – Ed S. Apr 17 '12 at 16:46
  • @JeroenLandheer that's not true. Simple example that throws exception and no warnings even with const strings (and I don't know where you got the "only const can be read by the compiler bit"): `const string format = "blabla{0}"; string x = string.Format(format);` – Mahmoud Al-Qudsi Apr 17 '12 at 16:47
  • 1
    @MahmoudAl-Qudsi: You don't understand why only a constant expression could be analyzed by the compiler? Why even ask a question if you already know the "correct" answer and are hostile to anyone who disagrees? – Ed S. Apr 17 '12 at 17:00
-1

I have filed a request for consideration of this feature on Microsoft Connect, as I feel that

  • The answers saying "people would prefer their code compile and fail at runtime if it's a not very hot codepath" is just absurd and has no place in non-interpreted languages, and especially not explicitly-defined, strongly-typed languages that place such an importance on type safety as C#.
  • The answers saying the compiler is physically not capable of (ever) deducing the format string and the parameters array at compile time are also incorrect. Yes, there are times when the compiler cannot deduce one or the other (or both) at compile time, and there's nothing that can be done about those, but many other times, it has the full info at its disposal.
  • The answers saying this is outright not the compiler's job just because the spec doesn't mention throwing a warning for this kind of behavior are missing the fact that the spec is the minimum that a compiler should implement, and the compiler is free (and does indeed to a great, great extent) to go above and beyond so long as it's not in conflict with the spec.
  • The answers saying C compilers don't do this either are plain wrong - I have posted examples otherwise.
  • The answers saying the code sample I posted does not throw an exception at runtime are blatantly wrong (though most have been edited since then).

At the end of the day, it's a "yes it could, no it doesn't, maybe it should" situation. I was trying to make sure that there wasn't something I could set in the compiler (not third party software) to make it more agressive with its warnings or if there were some way I could change my code to make it throw an exception (for instance, declaring everything as const), but it turns out (thus far) that that is not possible. Regardless of the response of the Visual Studio team on the issue I opened on MS Connect, the fact remains that the compiler certainly can catch a great many string formatting exceptions at compile time, that it would be a benefit... but it remains for the VS team to determine whether or not it is something worth implementing.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • 2
    gcc != "C compilers in general". Saying "C doesn't do this" is entirely correct, as it's not in the language specification. Has anyone claimed "No C compiler implementations do this"? That would be a different matter. – Jon Skeet Apr 19 '12 at 12:21
  • Hi Jon. Yep, the exact quote "I'm pretty sure the C/C++ compiler won't parse your printf format either... " – Mahmoud Al-Qudsi Apr 19 '12 at 18:23
  • Then I suggest you take issue with *that specifically* - and clarify your *own* statements which refer to things like "C/C++ will make a best effort to analyze your string format specifiers" - C and C++ are languages, not implementations. If you said "Some C and C++ compilers" that would be a lot more accurate. – Jon Skeet Apr 19 '12 at 18:27
  • Yes, you're right. That was an imprecise statement on my behalf. (though the intent should be clear as I said "C/C++ will make... compared to the C# compiler" (vs "compared to C#"). Just poor wording. – Mahmoud Al-Qudsi Apr 19 '12 at 21:27
  • That's still assuming there's only *one* C# compiler implementation, which isn't true. – Jon Skeet Apr 19 '12 at 21:28
  • I think it's clear that I'm referring to the stock Microsoft C# compiler (csc), for the latest version of the language, targeting the latest version of the runtime. _Although_, as a matter of fact, the complaint holds equally well for *any* past version of csc for any runtime version *AND* the Mono dmcs compiler, too. I don't know if there are any others out there, but that's all besides the point. Honestly, I love C# and this is all just constructive criticism to make the entire experience even more developer-friendly. I don't know why everyone is getting so defensive over this. – Mahmoud Al-Qudsi Apr 19 '12 at 21:31
  • I don't think your tone has helped, to be honest. I think you could have asked a similar question in a more constructive way (with more agreeable comments) and received rather more support. – Jon Skeet Apr 19 '12 at 21:36
  • 1
    I did lose my temper, and I'm sorry. But I was frustrated at the hivemind mentality of "let's defend C#, this guy is trying to say C++ is better," in the form of (some) factually incorrect, rushed answers. If you'll refer to the original post, it was very innocuous, inquisitive, and genuine. It was not my intention to start a war, and I'm sorry that's what it turned into. – Mahmoud Al-Qudsi Apr 19 '12 at 21:45
  • I think "blatantly clear bug" didn't start off too well - and I'd suggest that implying that the C# compiler really *should* do this (rather than it just being a nice feature to have) didn't help. Basically this is a *feature request*, but you imply that the compiler is *broken*. When you've written a question, read it through trying to put yourself in the place of the audience - it makes all the difference. – Jon Skeet Apr 19 '12 at 21:52
  • You're right. That could be easily misconstrued and I didn't think it through. The "blatantly clear bug" isn't in reference to C#, but in reference to a developer writing poor code that is obviously buggy upon further review. I think you would agree that the line of code posted in the OP contains a "blatantly clear bug?" I must have been misunderstood. – Mahmoud Al-Qudsi Apr 19 '12 at 21:55
  • No, the point is that it's only "blatantly clear" with information which depends on knowledge of the BCL - knowledge which *usually* isn't present. Basically what you're after is *something* like Code Contracts, but with more analysis. It's just not a game the C# compiler tries to play. It may be a reasonable feature request, but your "question" implies a level of disdain for the C# compiler which I don't think it warranted or helpful. It's also not clear why you were "under the impression" that the line given would trigger a compile-time *error* when it doesn't violate the language rules. – Jon Skeet Apr 19 '12 at 21:59
  • I have zero disdain for C# or its compiler. I love both. I just think it would be great to have this feature in there (best-effort style) or a good explanation for why not. I'm obviously not going to win here, but that's just my two cents. And as for being under the impression, well I've been accustomed to C# catching many bugs and giving warnings at compile time a lot better than C/C++ (my main coding languages). That's high praise and nothing less. Fact (IMHO): C# generally makes it easier to write more bug-free code than C/C++ the first time around. Hence my "impression." – Mahmoud Al-Qudsi Apr 19 '12 at 22:04