D - Re: Can we have context functions?
- Nic Tiger (80/80) Mar 15 2003 Hi Walter,
- Nic Tiger (21/101) Mar 19 2003 More thoughts: we can specify context parameters passed with this simple
- Farmer (48/57) Mar 24 2003 Hi.
- Nic Tiger (31/88) Mar 25 2003 Thanks for reply.
- Farmer (16/53) Mar 26 2003 Yes, making the __context keyord like extern(C) is quite appealing. I co...
- David Leonard (8/8) Apr 01 2003 How about a library module that allows access to the call stack?
- Sean L. Palmer (6/14) Apr 02 2003 You're basically making it mandatory for D to include a .map file or lin...
- Nic Tiger (7/15) Apr 02 2003 I want context functions to be fast and they *must not* interfere
- Sean L. Palmer (10/27) Apr 02 2003 The devil is in the details. Map files and debug info do not slow down ...
- Walter (2/2) Apr 02 2003 I think the concept is a good one, and addresses a problem I've wrestled
Hi Walter, Recently I thought a lot of concept which would provide support for logging and tracking without Cish macroses. This thoughts led me to the notion of context functions. DEFINITION. Context function is a function which accepts along with it's own parameters several hidden parameters such as FILE, LINE or FUNC. This hidden parameters are always passed when the function is called and have values describing the place where call is originated. Let's suppose that __context keyword enables us to define context function, and __file, __line, __func are keywords that designate hidden parameters inside context function. Now let's look at concepts of using logging and tracking in C and D. 1. Logging - the method to store some information along with description of it's sourse ============ C #define LogStr(str) DoWriteLogStr ( "%s,%d: %s\n", __FILE__, __LINE__, str ) ... main () { LogStr ("got here" ); ... LogStr ("got here" ); } ============ D __context void LogStr ( char[] str ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); } ... main () { LogStr ("got here" ); ... LogStr ("got here" ); } 2. Tracking - the method to determine who called particular function ============ C #define _malloc(s) malloc_tracked (s, __FILE__, __LINE__) void *malloc_tracked ( size_t size, char *file, int line ) { printf ("malloc(%d) from %s,%d\n", size, file, line ); return malloc ( size ); } main () { void *p = _malloc ( 10 ); } ============ D __context void *malloc ( size_t size ) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); // do allocation here... } main() { void *p = malloc ( 10 ); } ========================== end of examples Note that in D we not only got rid of preprocessor usage and have the identical behaviour, but also eliminated intermediate function malloc_tracked in the second example. As I see the implementation for this concept is trivial - pass context parameters to function just like you pass object pointer to class methods. The keywords used bear imagination. I don't think that names __context and others are perfect, but they are relevant to problem being solved. Another issue is that we need support via version statement in order to find out whether current function is context or not. Then we could rewrite the second example as: /*__context*/ void *malloc ( size_t size ) { version(__context) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); } // do allocation here... } And now we can turn functions into context functions and vice versa easily. I would like you to consider the examples given and say your word about it. Any critique and afterthought are welcome. Nic Tiger.
Mar 15 2003
More thoughts: we can specify context parameters passed with this simple syntax. __context(__file, __line) void LogStr ( char[] str ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); } Then only declared context parameter should be available inside context function. This simplifies compiler logic - simply pass context parameters function wanted. As for inapplicable context parameters (such as __class when calling not from member-function), the can be passed either NULL or "" (void string). I really would like to here anyone's opinion on this. Nic Tiger. "Nic Tiger" <nictiger progtech.ru> сообщил/сообщила в новостях следующее: news:b503u0$22db$1 digitaldaemon.com...Hi Walter, Recently I thought a lot of concept which would provide support forloggingand tracking without Cish macroses. This thoughts led me to the notion of context functions. DEFINITION. Context function is a function which accepts along with it's own parameters several hidden parameters such as FILE, LINE or FUNC. This hidden parameters are always passed when the function is called and have values describing the place where call is originated. Let's suppose that __context keyword enables us to define contextfunction,and __file, __line, __func are keywords that designate hidden parameters inside context function. Now let's look at concepts of using logging and tracking in C and D. 1. Logging - the method to store some information along with descriptionofit's sourse ============ C #define LogStr(str) DoWriteLogStr ( "%s,%d: %s\n", __FILE__, __LINE__, str ) ... main () { LogStr ("got here" ); ... LogStr ("got here" ); } ============ D __context void LogStr ( char[] str ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); } ... main () { LogStr ("got here" ); ... LogStr ("got here" ); } 2. Tracking - the method to determine who called particular function ============ C #define _malloc(s) malloc_tracked (s, __FILE__, __LINE__) void *malloc_tracked ( size_t size, char *file, int line ) { printf ("malloc(%d) from %s,%d\n", size, file, line ); return malloc ( size ); } main () { void *p = _malloc ( 10 ); } ============ D __context void *malloc ( size_t size ) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); // do allocation here... } main() { void *p = malloc ( 10 ); } ========================== end of examples Note that in D we not only got rid of preprocessor usage and have the identical behaviour, but also eliminated intermediate function malloc_tracked in the second example. As I see the implementation for this concept is trivial - pass context parameters to function just like you pass object pointer to class methods. The keywords used bear imagination. I don't think that names __context and others are perfect, but they are relevant to problem being solved. Another issue is that we need support via version statement in order tofindout whether current function is context or not. Then we could rewrite the second example as: /*__context*/ void *malloc ( size_t size ) { version(__context) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); } // do allocation here... } And now we can turn functions into context functions and vice versaeasily.I would like you to consider the examples given and say your word aboutit.Any critique and afterthought are welcome. Nic Tiger.
Mar 19 2003
Hi. Your idea of passing "compiler context" implicitly to functions seems very useful. I think, it could cover all common uses of the C preprocessor constants (__file, __line, etc.). Here are my critiques and afterthoughts ;-) What about making it look like a usual function, that has some parameters that are set implicitly by the compiler ? E.g. instead of__context(__file, __line) void LogStr ( char[] str ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); }void LogStr ( char[] str, char[] __file, int __line ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); } or shorter void LogStr ( char[] str, __file, __line ); or similar to C default parameters void LogStr ( char[] str, char[] fileName=__file, int lineNo=__line ) { printf ( "%.*s,%d: %.*s\n", fileName, lineNo, str ); } or void LogStr ( char[] str, __file fileName, __line lineNo) { printf ( "%.*s,%d: %.*s\n", fileName, lineNo, str ); } or use a context structure in order to safe keywords and make it more extendable: void LogStr( char[] str, __context ) { printf ( "%.*s,%d: %.*s\n", __context.file, __context.line, str ); } maybe you should be able to pass only some information of the context structure: void LogStr( char[] str, __context.file) { printf ( "%.*s,%d: %.*s\n", __context.file, __context.line, str ); } // above, __context.line is no longer valid. In some examples, I used the common D types int and char[]; to avoid any conflicts with argument overloading, the special context parameters should have their own type. Should be easy with typedef. One drawback compared with your proposed syntax is that versioning would require more typing, possibly cluttering interfaces a lot: version (tracedMalloc) void *malloc ( size_t size, __file, __line ) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); } else void *malloc ( size_t size) { printf ("malloc(%d) from %s,%d\n", size); } instead of just/*__context*/ void *malloc ( size_t size ) { version(__context) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); }But hey, you are cheating! __context is just commented out! That won't scale up to many functions. Farmer.
Mar 24 2003
Thanks for reply. I don't think it is convenient for programmer and for compiler vendor too to specify context functions via adding some magic names of parameters to function declaration. We don't add __class_object to all member functions, for example. Instead, we have it implicit and have access to it via this. Context functions are quite the same. And also we can make __context keyword working just like extern(C), for example; __context(__file, __line) void LogStr ( char[] str ) {...} or __context(__file, __line) { void LogStr ( char[] str ) {...} void Log2Str ( char[] str ) {...} // and so on. } Anyway, adding hidden parameters to function parameters list seems muddy for me. How can I understand that I should not pass this parameters and they are passed automatically by compiler? On overloading issue I would say that context functions are just like member function (from implementation point of view). We have overloaded member functions? Why do we get troubles with context ones? And also I would prohibited such declarations: __context(__file, __line) void LogStr ( char[] str ) {...} __context(__file) void LogStr ( char[] str ) {...} because they are ambiguous. Anyway I would like to hear Walter's opinion on that. Nic Tiger. "Farmer" <itsFarmer. freenet.de> сообщил/сообщила в новостях следующее: news:Xns9348E7CA7DABEitsFarmer 63.105.9.61...Hi. Your idea of passing "compiler context" implicitly to functions seems very useful. I think, it could cover all common uses of the C preprocessor constants (__file, __line, etc.). Here are my critiques and afterthoughts ;-) What about making it look like a usual function, that has some parameters that are set implicitly by the compiler ? E.g. instead of__context(__file, __line) void LogStr ( char[] str ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); }void LogStr ( char[] str, char[] __file, int __line ) { printf ( "%.*s,%d: %.*s\n", __file, __line, str ); } or shorter void LogStr ( char[] str, __file, __line ); or similar to C default parameters void LogStr ( char[] str, char[] fileName=__file, int lineNo=__line ) { printf ( "%.*s,%d: %.*s\n", fileName, lineNo, str ); } or void LogStr ( char[] str, __file fileName, __line lineNo) { printf ( "%.*s,%d: %.*s\n", fileName, lineNo, str ); } or use a context structure in order to safe keywords and make it more extendable: void LogStr( char[] str, __context ) { printf ( "%.*s,%d: %.*s\n", __context.file, __context.line, str ); } maybe you should be able to pass only some information of the context structure: void LogStr( char[] str, __context.file) { printf ( "%.*s,%d: %.*s\n", __context.file, __context.line, str ); } // above, __context.line is no longer valid. In some examples, I used the common D types int and char[]; to avoid any conflicts with argument overloading, the special context parameters should have their own type. Should be easy with typedef. One drawback compared with your proposed syntax is that versioning would require more typing, possibly cluttering interfaces a lot: version (tracedMalloc) void *malloc ( size_t size, __file, __line ) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); } else void *malloc ( size_t size) { printf ("malloc(%d) from %s,%d\n", size); } instead of just/*__context*/ void *malloc ( size_t size ) { version(__context) { printf ("malloc(%d) from %s,%d\n", size, __file, __line ); }But hey, you are cheating! __context is just commented out! That won't scale up to many functions. Farmer.
Mar 25 2003
"Nic Tiger" <nictiger progtech.ru> wrote in news:b5q2jt$1v3h$1 digitaldaemon.com:Thanks for reply. I don't think it is convenient for programmer and for compiler vendor too to specify context functions via adding some magic names of parameters to function declaration. We don't add __class_object to all member functions, for example. Instead, we have it implicit and have access to it via this. Context functions are quite the same. And also we can make __context keyword working just like extern(C), for example;Yes, making the __context keyord like extern(C) is quite appealing. I could think of __context(...) as a kind of calling convention, which it is from a implementation point of view.__context(__file, __line) void LogStr ( char[] str ) {...} or __context(__file, __line) { void LogStr ( char[] str ) {...} void Log2Str ( char[] str ) {...} // and so on. } Anyway, adding hidden parameters to function parameters list seems muddy for me. How can I understand that I should not pass this parameters and they are passed automatically by compiler?You should be able to pass these "context" parameters; a D compiler is merely kind enough to provide them for you. Sometimes an extra level of control is handy. It also makes calling a "context" function from outside D very obvious. Of course, when using your syntax, language interoperability isn't a problem, either.On overloading issue I would say that context functions are just like member function (from implementation point of view). We have overloaded member functions? Why do we get troubles with context ones?Right. There aren't any problems. I just commented on my own style of syntax. When using my syntax, overloading ambiguities could arise, as they do for default parameters in C++. By using non-standard types, these ambiguities can practically be avoided.And also I would prohibited such declarations: __context(__file, __line) void LogStr ( char[] str ) {...} __context(__file) void LogStr ( char[] str ) {...} because they are ambiguous. Anyway I would like to hear Walter's opinion on that.Ok, let's wait. Farmer.
Mar 26 2003
How about a library module that allows access to the call stack? Help stop feeping creaturism. import callstack; void LogStr(char[] str) { callstack.Frame f = callstack.getPreviousFrame(2); // caller's caller printf("%s:%d:%s(): %s\n", f.sourceFile, f.lineNo, f.symbol, str); }
Apr 01 2003
debug info in every executable. I doubt that'll fly, but yeah it'd be handy sometimes. Who knows? Sean "David Leonard" <david.leonard itee.uq.edu.au> wrote in message news:b6dn1k$cil$1 digitaldaemon.com...How about a library module that allows access to the call stack? Help stop feeping creaturism. import callstack; void LogStr(char[] str) { callstack.Frame f = callstack.getPreviousFrame(2); // caller's caller printf("%s:%d:%s(): %s\n", f.sourceFile, f.lineNo, f.symbol, str); }
Apr 02 2003
I want context functions to be fast and they *must not* interfere performance of all other code. Your approach is surely the way, but it could be very inefficient. I just want to get fast and useful tool for development. Nic Tiger. "David Leonard" <david.leonard itee.uq.edu.au> сообщил/сообщила в новостях следующее: news:b6dn1k$cil$1 digitaldaemon.com...How about a library module that allows access to the call stack? Help stop feeping creaturism. import callstack; void LogStr(char[] str) { callstack.Frame f = callstack.getPreviousFrame(2); // caller's caller printf("%s:%d:%s(): %s\n", f.sourceFile, f.lineNo, f.symbol, str); }
Apr 02 2003
The devil is in the details. Map files and debug info do not slow down the rest of the code, they're just big. Doing it some other way such as writing special info to the stack frames would slow the whole game down. How would you implement this library? There are libraries like this for C++. Don't we all want that? Sean "Nic Tiger" <nictiger progtech.ru> wrote in message news:b6f530$1g2r$1 digitaldaemon.com...I want context functions to be fast and they *must not* interfere performance of all other code. Your approach is surely the way, but it could be very inefficient. I just want to get fast and useful tool for development. Nic Tiger. "David Leonard" <david.leonard itee.uq.edu.au> сообщил/сообщила в новостях следующее: news:b6dn1k$cil$1 digitaldaemon.com...callerHow about a library module that allows access to the call stack? Help stop feeping creaturism. import callstack; void LogStr(char[] str) { callstack.Frame f = callstack.getPreviousFrame(2); // caller'sprintf("%s:%d:%s(): %s\n", f.sourceFile, f.lineNo, f.symbol, str); }
Apr 02 2003
I think the concept is a good one, and addresses a problem I've wrestled with for a while.
Apr 02 2003