Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[enh] Issue 5140 - Implement __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__ #1462

Merged
merged 1 commit into from Mar 7, 2013
Merged

Conversation

ghost
Copy link

@ghost ghost commented Jan 11, 2013

http://d.puremagic.com/issues/show_bug.cgi?id=5140

__FUNCTION__ is a common feature found in other languages and compilers. C99 defines it as __function__, although various compilers use their own naming (uppercase or lowercase, sometimes __func__).

List of compilers that I know of implementing the feature:

__FUNCTION__ will show the fully qualified name of the current function (when used as a statement in a function), or the calling function (when used in a parameter). If the function was called outside of a function scope (e.g. global enums initialized with CTFE), it returns an empty string.

__PRETTY_FUNCTION__ is similar, except it also shows the function modifiers and parameters.

__MODULE__ shows the fully qualified module name (which may be different from the file name). When used in a parameter it will show the fully qualified name of the module where the call was issued.

Expression *FuncInitExp::semantic(Scope *sc)
{
//printf("FuncInitExp::semantic()\n");
type = Type::tchar->invariantOf()->arrayOf();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type::tstring

@9rnsr
Copy link
Contributor

9rnsr commented Jan 11, 2013

I like __FUNC__ rather than __FUNCTION__. Because it is consistent with __FILE__ and __LINE__ on their identifier length.

@9rnsr
Copy link
Contributor

9rnsr commented Jan 11, 2013

If a function which has the __FUNCTION__ in its default argument, we cannot use it in CTFE?

bool func(string func = __FUNCTION__) { return true; }
enum b = func();  // CTFE in module scope
void main(){}

@ghost
Copy link
Author

ghost commented Jan 11, 2013

If a function which has the FUNCTION in its default argument, we cannot use it in CTFE?

Good point. I think in such a case __FUNCTION__ will have to become the function the parameter is part of, would that be ok?

@ghost ghost closed this Jan 11, 2013
@9rnsr
Copy link
Contributor

9rnsr commented Jan 11, 2013

I think in such a case FUNCTION will have to become the function the parameter is part of, would that be ok?

But, it seems to me that is an exceptional behavior of the design of __FUNCTION__. In such a case, I think the function should be given an empty string as a function name.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

But, it seems to me that is an exceptional behavior of the design of FUNCTION. In such a case, I think the function should be given an empty string as a function name.

Other languages probably don't have to deal with this due to the lack of CTFE, it's why I forgot about this test-case. An empty string could be good.

@andralex
Copy link
Member

Since __FILE__ and __LINE__ are referring to the caller location, __FUNCTION__ should refer to the caller function name. I'll add that this adds very interesting tracing capabilities to D.

@RobT2012
Copy link

This is very useful for tracing and logging function calls, for example I use this kind of thing for error logging. I'm very hopeful this is approved!

Does the proposed fix include a version that supplies the full function signature? The full function sig is required to distinguish which overloaded function was called, and what function template instantiation was called. This is rather important and should not be overlooked.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

Since FILE and LINE are referring to the caller location, FUNCTION should refer to the caller function name.

Yes, but only when used in the parameter list. When used as a statement it returns the current function name.

Does the proposed fix include a version that supplies the full function signature?

No, however we could use a separate __PRETTYFUNC__ which does that. Other compilers use this technique as well.

@ghost ghost reopened this Jan 11, 2013
@ghost ghost closed this Jan 11, 2013
@ghost
Copy link
Author

ghost commented Jan 11, 2013

I reopened so github would update its diff view. I'll try to implement PRETTY_FUNC, which will show the function signature. Edit: I'll just keep it opened while I work on it.

@ghost ghost reopened this Jan 11, 2013
@andralex
Copy link
Member

Nice. IMHO I think we should go with __FUNCTION__ instead of __FUNC__ although the latter does align nicely.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

Nice. IMHO I think we should go with FUNCTION instead of FUNC although the latter does align nicely.

If we implement a version with full type signature it will be easier to use __FUNC__ and __PRETTY_FUNC__ rather than __FUNCTION__ and __PRETTY_FUNCTION__. It will also help us keep code tight so it doesn't e.g. overflow our soft-limit line length in Phobos.

If we end up using __FUNC__ I could add a warning if the user tries to use __FUNCTION__ (maybe the user is a C++ programmer), e.g.: Error: __FUNCTION__ undefined, did you mean __FUNC__?

@andralex
Copy link
Member

If we issue that warning the natural question is, why didn't we name the bloody thing __FUNCTION__ in the first place. I think shortening both symbols is unneeded.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

Yeah, it might also help with porting C and C++ code to D if we use the longer version. I'll revert back to using the longer version.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

I have a little bit of a problem. __FUNCTION__ will return the fully qualified name, e.g. foo.bar.func, however this doesn't make much sense for __PRETTY_FUNCTION__ because the string will look like foo.bar.pure void func(int x, int y). So I'm thinking of maybe just outputting pure void func(int x, int y) without qualifications for the pretty func version. Thoughts?

@alexrp
Copy link
Member

alexrp commented Jan 11, 2013

My thought is that we need to stop putting pure and co. on the left-hand side of function definitions...

Though, yes, the unqualified version seems fine to me.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

Actually nevermind, I should simply use:

pure void foo.bar.func(int x, int y)

This is how GCC does it.

@RobT2012
Copy link

pure void foo.bar.func(int x, int y)

Yes, I was going to suggest that.

What does it do with class and struct function members?

@ghost
Copy link
Author

ghost commented Jan 11, 2013

Update: Implemented __PRETTY_FUNCTION__.

@ghost
Copy link
Author

ghost commented Jan 11, 2013

@RobT2012 See the test-case, it's in the diff view.

@jpf91
Copy link
Contributor

jpf91 commented Jan 11, 2013

If __FUNCTION__ returns the fully qualified name, will it be possible to split that into module / function at compile time so that no runtime code is needed?

If not it would probably be better to have a non-qualified __FUNCTION__ and add __MODULE__ as well?

@andralex
Copy link
Member

Yah, __FUNCTION__ is great as a qualified name that can be sliced and diced. That reminds me we should have a findLast algorithm. Wondering whether there's any need for __MODULE__.

@RobT2012
Copy link

@AndrejMitrovic
I think your test code is missing the nested function test case.
edit: I suppose functions under main() serve as the nest test case, but main is not a normal function.

@andralex
I'm unsure about the need for MODULE in terms of a use case, however it is likely that someone will want to use MODULE. I'd rather have it in place than not. Also note that FILE is not necessarily going to tell you what the module name is since the file name and module name may be completely different.

@andralex
Copy link
Member

I was just wondering how easy it is to figure the module from the qualified function name, i.e. if we have a.b.c.d what portion of that is the module?

@RobT2012
Copy link

I think it would be difficult to tell, perhaps impossible due to nested levels. A person may be able to figure it out, but not an algorithm unless the algorithm has access to the module name.

This does bring up a point: For logging purposes, we may not be able to tell which function was called when it's a nested function whose parent is overloaded or templated unless everything at levels above are fully qualified.

@andralex
Copy link
Member

We could figure module out via introspection, but that's arcane. I think __MODULE__ is in order too.

@andralex
Copy link
Member

Things are fine as they are. File and line belong together, but a template that wants to trace by module would take __MODULE__ as a default template argument etc. If instead it took __CONTEXT__ there would be one instantiation per call. Then we'd need to ascribe __CONTEXT__ a type and all that crap. Let's just stop. Things are good as they are.

@jpf91
Copy link
Contributor

jpf91 commented Jan 12, 2013

If we have __MODULE__ now, should __FUNCTION still contain the module name or not? In both cases it's easy enough to get the other form:

auto full = __MODULE__ ~ __FUNCTION__;
auto part = __FUNCTION__;

//vs

auto full = __FUNCTION__;
auto part = __FUNCTION__[__MODULE__.length .. $];

@ghost ghost closed this Jan 12, 2013
@ghost ghost reopened this Jan 12, 2013
@RobT2012
Copy link

Just consider that we should always try and avoid unnecessary memory allocations during runtime.

For me, the primary use is for logging, so I would normally always append the full module name, and always use the full signature form of the function. Someone else however may have different needs.

@ghost
Copy link
Author

ghost commented Jan 12, 2013

This crashes but only with -property switch:

mixin template T()
{
    string fact()
    {
        mixin("return " ~ __FUNCTION__ ~ "();");
    }
}

void main()
{
    mixin T!() X;  // __FUNCTION__ = test.main.T!().fact
}

However it's unrelated to this pull, I've filed it as Issue 9303.

@ghost
Copy link
Author

ghost commented Jan 12, 2013

I prefer to leave them fully-qualified to avoid bugs from any eventual abuse. Someone might end up using them in metaprogramming to issue function calls. I want them to get a compiler error if the function is wrongly-qualified rather than accidentally picking up some function that happens to be defined in the current scope.

.stringof, __FUNCTION__, and similar functionality should be used for logging, exception messages and debugging, not for metaprogramming. But there's always abuse regardless of warnings (e.g. see how Phobos checks for whether a type has a destructor).

@andralex
Copy link
Member

I think a typical use case is:

void fun(string caller = __FUNCTION__)(int x, double y) { ... }

If __FUNCTION__ contains the full name, then this works out of the box (one instantiation per caller function). Otherwise people would need to also have a template parameter defaulted to __MODULE__.

@ghost ghost closed this Jan 12, 2013
@ghost ghost reopened this Jan 18, 2013
@ghost
Copy link
Author

ghost commented Jan 18, 2013

Reopened after implementing template argument support. It didn't originally work as templates do not pass the right calling scope when issuing a call to resolveLoc, therefore I've had to add a new field to the Scope struct called callsc. With this I can resolve both the function and the module of the invocation site when template default arguments are involved.

Note that the reason __FILE__ and __LINE__ didn't have this problem is because they've used loc internally, not the scope from the sc parameter.

@ghost
Copy link
Author

ghost commented Feb 12, 2013

Fixed-up failure due to another pull affecting output, should be ready for a merge after green.

@nazriel
Copy link
Contributor

nazriel commented Mar 6, 2013

Bump. It is rather useful addition.
Seems to be all green.

@andralex any final words about it?

@andralex
Copy link
Member

andralex commented Mar 7, 2013

Sweet! I'll merge now. cc @WalterBright

andralex added a commit that referenced this pull request Mar 7, 2013
[enh] Issue 5140 - Implement __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
@andralex andralex merged commit fd628d8 into dlang:master Mar 7, 2013
@braddr
Copy link
Member

braddr commented Mar 7, 2013

Don't forget to add appropriate documentation for these changes.

@ghost
Copy link
Author

ghost commented Mar 7, 2013

Don't forget to add appropriate documentation for these changes.

Yeah. Btw, we should have some kind of collective name for all these magic keywords so we know how to refer to them. What would be a good name for these?

@andralex
Copy link
Member

andralex commented Mar 7, 2013

"Special constants"

@RobT2012
Copy link

RobT2012 commented Mar 7, 2013

Excellent! I'll try using these new functions asap. Big thanks for the effort!

@RobT2012
Copy link

RobT2012 commented Mar 7, 2013

I was going to suggest something along the lines of "reflection" or "introspection" but it doesn't really matter so long as there's a reasonable name for them.

One question is where in the docs is best for this stuff?

@ghost
Copy link
Author

ghost commented Mar 7, 2013

"Special constants"

Well they're not really "constant" per say. I was just about to use "special keywords", but it can go either way.

Edit: I mean "special tokens", this would sound nice.

@ghost
Copy link
Author

ghost commented Mar 7, 2013

One question is where in the docs is best for this stuff?

They're already in template.html, I'll just add new links, put the new docs in and make a code example.

@ghost
Copy link
Author

ghost commented Mar 7, 2013

Well they're not really "constant" per say. I was just about to use "special keywords", but it can go either way.

Argh I wanted to say "Special Tokens".

@RobT2012
Copy link

RobT2012 commented Mar 7, 2013

They're already in template.html, I'll just add new links, put the new docs in and make a code example.

Why in templates? These "special keywords" can be used in non-templated situations, in addition I would never think to look in a section about templates when looking for something like this.

traits.html seems more appropriate to me.

@andralex
Copy link
Member

andralex commented Mar 7, 2013

I think the're actually special constants. You can't e.g. do LINE++.

@RobT2012
Copy link

RobT2012 commented Mar 7, 2013

Now that this is done, perhaps class Throwable and derivatives should be extended to include the function name?

@yebblies
Copy link
Member

yebblies commented Mar 8, 2013

"Context expressions"
They're a little more magical than 'constant' implies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
10 participants