string file = __FILE__ considered harmful (and solution)

Steven Schveighoffer schveiguy at yahoo.com
Wed May 30 14:40:50 UTC 2018


On 5/30/18 4:27 AM, FeepingCreature wrote:
> There's a very common idiom where in order to report line numbers of an 
> error or a log line at the callsite of a function, you pass __FILE__ and 
> __LINE__ as default parameters:
> 
> void foo(string file = __FILE__, size_t line = __LINE__);
> 
> What's wrong with this?
> 
> Say you add a string parameter, such as
> 
> void foo(string msg, string file = __FILE__, size_t line = __LINE__);
> 
> foo("Hello World");
> 
> Now when you accidentally grab an old version of the library, your new 
> code will still run, but it will believe that it's being called from 
> file "Hello World", line 15. Not good.
> 
> Luckily there's a fix. Just stick this in some common header file in 
> your project:
> 
> struct CallerInfo
> {
>    string file;
>    size_t line;
> }
> 
> void foo(string msg, CallerInfo caller = CallerInfo(__FILE__, __LINE__));
> 
> Now you cannot accidentally invoke foo with a string, or in fact any 
> type except another instance of CallerInfo.

Awesome idea! Unfortunately, it doesn't work. The __FILE__ and __LINE__ 
there are not from the caller, but from the line that defines foo.

See here: https://run.dlang.io/is/siz9YZ

> At which point we can shorten this to CallerInfo caller = 
> __CALLER__, and be forward compatible for additional information about 
> the callsite, such as, say, attributes of the calling function.

Hm.. I don't like this too much. Adding more magic to the compiler seems 
unnecessary.

But if we fixed the behavior that causes your idea not to work, then we 
could probably easily define a function like so:

CallerInfo __CALLER__(string file = __FILE__, size_t line = __LINE__)
{
     return CallerInfo(file, line);
}

-Steve


More information about the Digitalmars-d mailing list