Add __POS__ as a more concise (__FILE__, __MODULE__, __LINE__).
Add a "struct Pos { string file, module; size_t line; }" in a core library somewhere.
Add a __POS__ magical constant that evaluates to Pos(__FILE__, __MODULE__, __LINE__) but is evaluated at the correct position (equivalent to manually placing __FILE__, __MODULE__, __LINE__ into separate compile-time variables.
Comment #1 by dlang-bugzilla — 2017-07-05T01:40:11Z
I think such an enhancement could use some more background.
When would you find it useful, and how are the existing tools insufficient to warrant a change in the language?
Right now, you can use:
- string mixins, i.e.:
Pos pos = mixin(mixPos);
where
enum mixPos = q{ Pos(__FILE__, __MODULE__, __LINE__) };
- The property of __FILE__/__LINE__ etc. that as default arguments, they are evaluated at the call site:
Pos pos = getPos();
where
Pos getPos(string f=__FILE__, string m=__MODULE__, int l=__LINE__)
{ return Pos(f, m, l); }
- As above, but also for template arguments, not just runtime function arguments:
Pos pos = currentPos!();
where
enum Pos currentPos(string f=__FILE__, string m=__MODULE__, int l=__LINE__) = Pos(f, m, l);
(I haven't tested the above, but I think they should work.)
Comment #2 by eyal — 2017-07-05T07:46:05Z
I tested the mixin approach before filing this. It doesn't work:
struct Pos { size_t line; }
void foo(size_t line=__LINE__, Pos pos=Pos(__LINE__))() { .. }
line is caller's line. pos.line is foo's decl line.
The reason I want this enhancement is that we have a logging framework that uses the line numbers in compile-time (to make fast logs that log very minimally at runtime).
I often want to create log-line wrappers for specific cases.
Currently I have to do this:
void myLogger(string fmt, string file=__FILE__, string mod=__MODULE__, size_t line=__LINE__, Args...)(auto ref Args args) {
log!("my extra stuff" ~ fmt, file, mod, line)(myExtraArgs, args);
}
And this has to be repeated, verbatim, for every log wrapper in existence.
It is quite a big discouragement against writing functions that work and pass on code positions.
Much nicer:
void myLogger(string fmt, Pos pos=__POS__) {
log!("my extra stuff" ~ fmt, pos)(myExtraArgs, args);
}
Almost as nice:
void myLogger(string fmt, Pos pos=mixin(POS)) ...
So alternatively to adding __POS__, dmd could be fixed so that __LINE__ is based on its *lexical* position. i.e: same value for __LINE__ in a default CT param value and when it is given to Pos() inside a default CT param value.
Comment #3 by b2.temp — 2017-07-05T10:51:40Z
I manage to make the feature working with a tuple after a quick hacking session, with this code that compiles and runs and then displays the expected result:
====
module runnable;
import std.stdio, std.typecons;
void foo(Tuple!(string, string, int) p = __POS__)
{
writeln(p);
}
void main(string[] args)
{
writeln(__POS__[0]);
writeln(__POS__[1]);
writeln(__POS__[2]);
foo();
}
====
actually more can be added to the tuple. (here it's the equivalent of __FILE__, __MODULE__ then __LINE__) since __PRETTY_FUNCTION__ is also important for logging.
If DMD people agree on the principle of the feature I'm not against proposing a PR. Also with a small bounty as motivation if possible.
Comment #4 by dlang-bugzilla — 2017-07-05T11:59:08Z
(In reply to Eyal from comment #2)
> So alternatively to adding __POS__, dmd could be fixed so that __LINE__ is
> based on its *lexical* position. i.e: same value for __LINE__ in a default
> CT param value and when it is given to Pos() inside a default CT param value.
That seems like the way to go here IMO. As described, __POS__ seems a bit too specific to your logging framework, whereas the above should be a more universal improvement.
Comment #5 by b2.temp — 2017-07-05T14:01:43Z
The tuple solution while working is not ideal, tuple type is not infered so it cannot be upgraded automatically if the internal DMD tuple member changes.
Comment #6 by robert.schadek — 2024-12-13T18:53:05Z