Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 15, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
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. |
March 19, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nic Tiger | 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 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. > > |
March 24, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nic Tiger | 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. |
March 25, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Farmer | 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. |
March 26, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nic Tiger | "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. |
April 02, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Farmer | 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); } |
April 02, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Leonard | You're basically making it mandatory for D to include a .map file or line # 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); > } |
April 02, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Leonard | 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); > } > > |
April 02, 2003 Re: Can we have context functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nic Tiger | 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... > > 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); > > } |
Copyright © 1999-2021 by the D Language Foundation