Bug 5140 – Add __FUNCTION__, __PRETTY_FUNCTION__, and __MODULE__
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
All
Creation time
2010-10-30T20:28:00Z
Last change time
2013-03-07T07:46:10Z
Keywords
pull
Assigned to
andrej.mitrovich
Creator
issues.dlang
Comments
Comment #0 by issues.dlang — 2010-10-30T20:28:59Z
D has __FILE__ and __LINE__ which give the file and line number where they're used. C/C++ has those as well, but (at least with some implementations) it also has __FUNCTION__ which gives the name of the function where it's used, which can be quite useful (especially when you use it in a logging message, and you don't necessarily know which version of the program the message comes from). So, I think that it would be benificial to add __FUNCTION__ to D. Honestly, I was surprised when it wasn't in the language while __FILE__ and __LINE__ were.
Comment #1 by bearophile_hugs — 2010-10-31T05:56:56Z
It also allows code like this, this recursive code will keep working even if "fact" gets renamed, it's more DRY:
long fact(long n) {
if (n <= 1)
return 1;
else
mixin("return n * " ~ __FUNCTION__ ~ "(n - 1);");
}
void main() {
assert(fact(20) == 2_432_902_008_176_640_000);
}
But an alias of the current function is more handy for that purpose:
long fact(long n) {
if (n <= 1)
return 1;
else
return n * __function(n - 1);
}
void main() {
assert(fact(20) == 2_432_902_008_176_640_000);
}
Comment #2 by bearophile_hugs — 2011-04-16T15:36:18Z
I'd like to add that __FUNCTION__ should operate in a consistent manner to __LINE__ and __FILE__ such that when used as a default value for a function parameter, the value is set where the function is called, not where the function is defined.
void Log( string funcname = __FUNCTION__)
{
writeln( funcname );
}
void func1()
{
Log(); // displays "func1"
}
void main()
{
Log(); // displays "main"
}
To be more useful, the nested function names will have to prefixed with parent level function names, and probably also module name as the highest level.
void main()
{
void func2()
{
Log(); // displays "main.func2"
}
}
Member functions of class and struc should be prefixed with the class and struc names respectively.
For templates and overloaded functions, including the function signature would help resolve which version of a function was called. It may be best to have a separate version of __FUNCTION__ that displays the function signature, for example, C++ has __PRETTY_FUNCTION__ which includes the function signature.
Comment #4 by andrej.mitrovich — 2013-01-10T19:44:58Z
Comment #5 by bearophile_hugs — 2013-01-10T20:23:21Z
If __FUNCTION__ gets approved, then probably the probability of __function getting approved decreases. And I don't care for __FUNCTION__.
Comment #6 by alanb — 2013-01-10T23:24:01Z
(In reply to comment #2)
> See a better explanations and some examples of __function:
> http://rosettacode.org/wiki/Anonymous_recursion
>
I really would love to have the ability to perform anonymous recursion.
As for the name __FUNCTION__ I don't really like the convention either, but since it is related to __LINE__ and __FILE__, you'd probably have to depreciate those too so as to remain consistent.
This is great news if it gets accepted because I need it for log tracing, but I'd also like to see a version of this that displays the full function signature which allows you to see which overload or template version was called. I don't know if the patch does this or not.
--rt
Comment #7 by issues.dlang — 2013-01-11T00:05:34Z
__FUNCTION__ is already used by some C/C++ compilers just like __FILE__ and __LINE__, so there's a fair bit of precedence for it, and it goes well with __FILE__ and __LINE__.
Personally, I don't care about anonymous recursion and see no need for them, but I don't see __FUNCTION__ as conflicting with __function at all. They do two entirely different things. __FUNCTION__ is a string, whereas __function is an alias to the function that it's used in.
Comment #8 by bearophile_hugs — 2013-01-11T01:28:47Z
Sorry Andrej, my last comment wasn't a critique of your good work in pull 1462.
(In reply to comment #7)
> but I don't see __FUNCTION__ as conflicting with __function at all. They do two
> entirely different things. __FUNCTION__ is a string, whereas __function is an
> alias to the function that it's used in.
I agree they are two quite different things, so probably I have to move the request for __function in another enhancement request.
But they are also related, as you can implement anonymous recursion with __FUNCTION__:
long fact(long n) {
if (n <= 1)
return 1;
else
mixin("return n * " ~ __FUNCTION__ ~ "(n - 1);");
}
So I think introducing __FUNCTION__ will make less likely the introduction of the __function alias. I hope to be wrong.
> Personally, I don't care about anonymous recursion and see no need for them,
Are you using recursion a lot in D? If you never use recursion in D, or you use it only once in thousand lines of code, then you don't have much need for language features that help using recursion, like __func (or private default arguments discussed recently).
If you use recursion often, an alias like __func or __function gets useful, because it allows you to write more DRY code, you write the function name only once. So renaming the function or other changes requires you to change only one name.
It's like the difference between D OOP and Java, this is Java-like code:
class Foo {
Foo(int x) {...}
void bar(Foo f) {
Foo g = new Foo(5);
...
}
}
This is one possible equivalent D code:
class Foo {
this(int x) {...}
void bar(typeof(this) f) {
auto g = new typeof(this)(5);
...
}
}
This D code contains the name Foo only once, this is more DRY, and it's useful.
Comment #9 by issues.dlang — 2013-01-11T01:32:52Z
I simply don't see any need to refer to a function anonymously when making a recursive call. You can just use its name like you do anywhere else that you call it. The _only_ advantage that I see is that you have fewer lines of code to change when you change the function's name, but search and replace takes care of that quite easily.
I'm not necessarily against the inclusion of __function. I just don't find the idea useful enough to care.
Comment #10 by bearophile_hugs — 2013-01-11T01:54:52Z
(In reply to comment #9)
> I simply don't see any need to refer to a function anonymously when making a
> recursive call. You can just use its name like you do anywhere else that you
> call it. The _only_ advantage that I see is that you have fewer lines of code
> to change when you change the function's name, but search and replace takes
> care of that quite easily.
Do you mean you wish/prefer to write OOP like this in D?
class Foo {
Foo(int x) {...}
void bar(Foo f) {
Foo g = new Foo(5);
...
}
}
Comment #11 by doob — 2013-01-11T02:33:23Z
(In reply to comment #8)
> Sorry Andrej, my last comment wasn't a critique of your good work in pull 1462.
>
> (In reply to comment #7)
>
> > but I don't see __FUNCTION__ as conflicting with __function at all. They do two
> > entirely different things. __FUNCTION__ is a string, whereas __function is an
> > alias to the function that it's used in.
>
> I agree they are two quite different things, so probably I have to move the
> request for __function in another enhancement request.
>
> But they are also related, as you can implement anonymous recursion with
> __FUNCTION__:
>
>
> long fact(long n) {
> if (n <= 1)
> return 1;
> else
> mixin("return n * " ~ __FUNCTION__ ~ "(n - 1);");
> }
>
>
> So I think introducing __FUNCTION__ will make less likely the introduction of
> the __function alias. I hope to be wrong.
Can't __FUNCTION__ be implemented like this:
__traits(identifier, __function);
That is, if __function gets implemented.
Comment #12 by clugdbug — 2013-01-11T04:52:46Z
(In reply to comment #11)
> (In reply to comment #8)
> > Sorry Andrej, my last comment wasn't a critique of your good work in pull 1462.
> >
> > (In reply to comment #7)
> >
> > > but I don't see __FUNCTION__ as conflicting with __function at all. They do two
> > > entirely different things. __FUNCTION__ is a string, whereas __function is an
> > > alias to the function that it's used in.
> >
> > I agree they are two quite different things, so probably I have to move the
> > request for __function in another enhancement request.
> >
> > But they are also related, as you can implement anonymous recursion with
> > __FUNCTION__:
> >
> >
> > long fact(long n) {
> > if (n <= 1)
> > return 1;
> > else
> > mixin("return n * " ~ __FUNCTION__ ~ "(n - 1);");
> > }
> >
> >
> > So I think introducing __FUNCTION__ will make less likely the introduction of
> > the __function alias. I hope to be wrong.
>
> Can't __FUNCTION__ be implemented like this:
>
> __traits(identifier, __function);
>
> That is, if __function gets implemented.
No. It needs magical treatment when used as a default parameter.
Comment #13 by doob — 2013-01-11T05:02:28Z
(In reply to comment #12)
> No. It needs magical treatment when used as a default parameter.
Right, didn't think of that.
Comment #14 by alanb — 2013-01-11T09:29:13Z
(In reply to comment #10)
> (In reply to comment #9)
> > I simply don't see any need to refer to a function anonymously when making a
> > recursive call. You can just use its name like you do anywhere else that you
> > call it. The _only_ advantage that I see is that you have fewer lines of code
> > to change when you change the function's name, but search and replace takes
> > care of that quite easily.
>
> Do you mean you wish/prefer to write OOP like this in D?
>
>
> class Foo {
> Foo(int x) {...}
> void bar(Foo f) {
> Foo g = new Foo(5);
> ...
> }
> }
Good points. I know what you say is true because I use recursion often enough to see the advantages. The case for private default args is another solid argument.
More generically speaking however, rather than being ad-hoc less-than-useful, what is being proposed actually makes some of D's features more consistent with the rest of D. For example the use of private args is more consistent with the rest of D's features that already have private, such as structs, classes, and modules. Disallowing private args is actually less consistent with the rest of D and is a throw-back to the C era. The _function is actually consistent with the use of "this" for structs and classes. Had these private args and anonymous recursion been implemented from the start, the thought of removing them would never be considered. If we had the chance to redesign D, we could actually make it simpler to use and more powerful by making it more consistent.
--rt
Comment #15 by andrej.mitrovich — 2013-01-11T10:04:38Z
The pull now implements __FUNCTION__ and __PRETTY_FUNCTION__. You can take a look at the test-case for examples, but in short:
1) __FUNCTION__ as a statement inside a function => fully-qualified name of the current function
2) __FUNCTION__ as a default init for a parameter => fully-qualified name of the calling function
3) __PRETTY_FUNCTION__ as a statement inside a function => same as #1 + parameters, return type, and modifiers.
4) __PRETTY_FUNCTION__ as a default init for a parameter => same as #2 + parameters, return type, and modifiers.
If either of these is called in module scope (e.g. enum which is initialized with UFCS), it will return an empty string.
Comment #16 by bearophile_hugs — 2013-01-11T10:28:43Z
(In reply to comment #15)
> If either of these is called in module scope (e.g. enum which is initialized
> with UFCS), it will return an empty string.
A question: isn't it better to give a compilation error in this case, instead of returning an empty result?
Comment #17 by andrej.mitrovich — 2013-01-11T12:31:38Z
(In reply to comment #16)
> (In reply to comment #15)
>
> > If either of these is called in module scope (e.g. enum which is initialized
> > with UFCS), it will return an empty string.
>
> A question: isn't it better to give a compilation error in this case, instead
> of returning an empty result?
No, because it would make the function unusable in CTFE in some contexts.
Comment #18 by andrej.mitrovich — 2013-01-11T16:36:57Z
The enhancemented now includes __MODULE__ as requested by Andrei and others.
Comment #19 by andrej.mitrovich — 2013-01-11T19:39:54Z
*** Issue 2909 has been marked as a duplicate of this issue. ***
Comment #20 by andrej.mitrovich — 2013-01-12T10:28:13Z
(In reply to comment #8)
> > entirely different things. __FUNCTION__ is a string, whereas __function is an
> > alias to the function that it's used in.
>
> I agree they are two quite different things, so probably I have to move the
> request for __function in another enhancement request.
Please make another enhancement request for this, so it's not forgotten and we can wait for a separate approval.
Comment #21 by andrej.mitrovich — 2013-01-12T10:42:15Z
(In reply to comment #8)
> But they are also related, as you can implement anonymous recursion with
> __FUNCTION__:
>
>
> long fact(long n) {
> if (n <= 1)
> return 1;
> else
> mixin("return n * " ~ __FUNCTION__ ~ "(n - 1);");
> }
This is unreliable. If `fact` is nested inside of a mixin template you won't be able to call the function this way. On another note this has uncovered a new ICE in Issue 9182.
It's also very untidy to have to use mixins and string representation for recursive calls. It's much simpler to use 'return __function(n - 1)'.
Comment #22 by bearophile_hugs — 2013-01-12T13:47:44Z
(In reply to comment #20)
> Please make another enhancement request for this, so it's not forgotten and we
> can wait for a separate approval.
OK. See Issue 9306
Comment #23 by github-bugzilla — 2013-03-06T20:02:48Z