www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Sick proposal!

reply h3r3tic <h3r3tic dev.null> writes:
Ok, call me insane, but I think it would be really nice to have 
something along these lines supported in D:

functype traced
{
     version (debug)
     {
         in {
             // writefln("Entering ", name);
         }
		
         out {
             // writefln("Exiting ", name);
         }

         except(Object x) {
             writefln("Exception caught in function ", name);
         }
     }
}


And then write:

void foo() traced
{
}


It wouldn't be that hard thing to do, although the parsing rules for 
functions would have to be altered to support the additional type 
specifier. The in and out blocks could actually be added to the 
function's in and out blocks and if any except block was defined in the 
functype, the function could be wrapped in a try block and then the 
exceptions could be handled.
name would be replaced by the function name, in this one case, "foo".
Moreover, the functype thingie might also take some optional parameters.

Probably not a 1.0 thing though ;) but I can see no other way to have 
nice traces of where an error has occured (unless we get nice stack 
traces) and this could prove to be useful after all. If I don't get a 
similar feature or stack traces that can nicely print a function call 
tree, I'm writing a preprocessor for D. There are so many cool things 
that can be done with it that sometimes the lack of a preprocessor in D 
is a real hit...
Jul 30 2004
next sibling parent h3r3tic <h3r3tic dev.null> writes:
actually it would be better to follow the class way:

void foo() : traced
{
}

that way, there could be a list of functype's, like

void foo() : traced, logged("myLog.txt")
{
}
Jul 30 2004
prev sibling next sibling parent reply Ant <duitoolkit yahoo.ca> writes:
On Sat, 31 Jul 2004 02:00:26 +0200, h3r3tic wrote:

 Ok, call me insane, but I think it would be really nice to have 
 something along these lines supported in D:
 
 functype traced
 {
      version (debug)
      {
          in {
              // writefln("Entering ", name);
          }
 		
          out {
              // writefln("Exiting ", name);
          }
 
          except(Object x) {
              writefln("Exception caught in function ", name);
          }
      }
 }
 
 
 And then write:
 
 void foo() traced
 {
 }
An IDE for D could easely add and remove the print outs and/or the in and out blocks. Ant my editor for D: http://leds.sourceforge.net
Jul 30 2004
parent h3r3tic <h3r3tic dev.null> writes:
 An IDE for D could easely add and remove the print outs and/or
 the in and out blocks.
Yeah, I know, but the code gets very clumsy really fast. It's again about hiding the implementation, so I can just say: void foo() : traced { ... } instead e.g. void foo() { debug { auto CallTrace trace__ = new CallTrace("foo"); } ... } I think the first one is more eye-friendly
Jul 30 2004
prev sibling next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"h3r3tic" <h3r3tic dev.null> wrote in message
news:ceeufl$e8n$1 digitaldaemon.com...
 Probably not a 1.0 thing though ;) but I can see no other way to have
 nice traces of where an error has occured (unless we get nice stack
 traces) and this could prove to be useful after all. If I don't get a
 similar feature or stack traces that can nicely print a function call
 tree, I'm writing a preprocessor for D. There are so many cool things
 that can be done with it that sometimes the lack of a preprocessor in D
 is a real hit...
It's no problem at all. Write an auto class: auto class Tracer { char[] name; this(char[] name) { this.name = name; fwriteln("entry ", name); } ~this() { fwriteln("exit ", name); } } And use it like: void foo() { Tracer T = new Tracer("foo"); ... } You can add some complexity to it to track the stack frames. Or, you can compile with -gt and look at how the trace code figures it out. www.digitalmars.com/ctg/trace.html
Jul 31 2004
parent reply h3r3tic <h3r3tic dev.null> writes:
ok, let me try your approach for a second... is there a function in D 
which checks if an exception has been thrown ? like the 
uncaught_exception() in c++ ?
Aug 01 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"h3r3tic" <h3r3tic dev.null> wrote in message
news:ceii92$1vk7$1 digitaldaemon.com...
 ok, let me try your approach for a second... is there a function in D
 which checks if an exception has been thrown ?
No, but there is the catch() statement.
 like the
 uncaught_exception() in c++ ?
Aug 01 2004
parent h3r3tic <h3r3tic dev.null> writes:
Walter wrote:
 "h3r3tic" <h3r3tic dev.null> wrote in message
 news:ceii92$1vk7$1 digitaldaemon.com...
 
ok, let me try your approach for a second... is there a function in D
which checks if an exception has been thrown ?
No, but there is the catch() statement.
like the
uncaught_exception() in c++ ?
then do this: auto class Foo() { ~this() { catch(Exception blah) { writefln("exc caught"); } } } void bar() { auto Foo X = new Foo; throw Exception("geez"); } void main() { bar(); } and see what happens I REALLY meant an utility with the functionality of uncaught_exception()... :/
Aug 01 2004
prev sibling next sibling parent reply pragma <EricAnderton at yahoo dot com> <pragma_member pathlink.com> writes:
In article <ceeufl$e8n$1 digitaldaemon.com>, h3r3tic says...
Ok, call me insane, but I think it would be really nice to have 
something along these lines supported in D:

functype traced
{
     version (debug)
     {
         in {
             // writefln("Entering ", name);
         }
		
         out {
             // writefln("Exiting ", name);
         }

         except(Object x) {
             writefln("Exception caught in function ", name);
         }
     }
}


And then write:

void foo() traced
{
}
Actually just allowing "super()" outside of the constructor would probably be all that's needed to get this to work inside classes. Its still an interesting idea, but wouldn't this work better if it were treated like class inheritance? void baseFunction() in{ writefln("base in"); } body{ writefln("base body"); } out{ writefln("base out"); } // concreteFunction "inherits" baseMethod void concreteFunction(): baseFunction in{ writefln("concrete in"); } body{ super(); writefln("concrete body"); } out{ writefln("concrete out"); } // test void main(){ concreteFunction(); } Which would generate the output: base in concrete in base body (via opional call to super()) concrete body base out concrete out It'd be interesting to see what someone could do if this syntax were allowed to "rewire" a class' v-table by specifying overrides on a method-by-method basis. (I'd imagine the result to be a gross perversion of D's method inheritance rules) I'd also reckon that Typeinfo would have to go through some contortions to allow a method's inheritance to be discovered. Is D's stack tracing code (+gt) in phobos at all, or is this done inside the compiler only? If phobos could also contain an implicit base method/function much like Object is for classes, that utilizes this mechanism, could that feature be more easily maintained? - Pragma
Aug 01 2004
parent reply h3r3tic <h3r3tic dev.null> writes:
pragma <EricAnderton at yahoo dot com> wrote:
 Its still an interesting idea, but wouldn't this work better if it were treated
 like class inheritance?
 
 void baseFunction()
 in{ writefln("base in"); }
 body{ writefln("base body"); }
 out{ writefln("base out"); }
 
 // concreteFunction "inherits" baseMethod
 void concreteFunction(): baseFunction
 in{ writefln("concrete in"); }
 body{ super(); writefln("concrete body"); }
 out{ writefln("concrete out"); }
 
 // test
 void main(){
 concreteFunction();
 }
 
 Which would generate the output:
 
 base in
 concrete in
 base body (via opional call to super())
 concrete body
 base out
 concrete out
Yeah, it's even better. Though I'd add a new available block type to the design by contract thingie for functions, so that one could do: void foo() in { ... } out { ... } body { ... } catch(...) {...} on the whole function level so that exception handling could be inherited as well. Let me now write some hypothetical "D with function inheritance code" void guarded() body { } catch(Exception err) { writefln("Exception caught in func ", thisfunc.name); throw; } void foo() : guarded { bar(); } void bar() : guarded { throw Exception("FUBAR"); } void main() { try { foo(); } catch(Exception err) { writefln(err); // here typeinfos are repaired so I don't have to type err.toString() ;) } } Which would produce: Exception caught in func bar Exception caught in func foo Exception <- or whatever Exception.toString() produces Hmmmmmm... wouldn't function inheritance be the great one feature that other languages don't have ? How to do it ? I'm not a compiler writer buy in my opinion, Python's approach is nice: def foo(): some code the def statement just creates a new object whose opCall is set to execute the code given. This could work more or less the same in D. Any oppinions/comments/flames/bitchslaps ?
Aug 01 2004
parent h3r3tic <h3r3tic dev.null> writes:
 Hmmmmmm... wouldn't function inheritance be the great one feature that 
 other languages don't have ?
Damn. Note to self: first think, then think, then think a lil bit more, ONLY then post here... This couldn't be a killer feature. There isn't too much to inherit but the DbC blocks (+ the proposed throw block) so it would rather be an extension to the DbC, not a killer... sorry ;)
Aug 01 2004
prev sibling next sibling parent reply Regan Heath <regan netwin.co.nz> writes:
This idea is close to the 'aspect oriented programming' idea, or rather 
with a little extending could be used for aspect oriented programming.

The idea behind aspect oriented programming is that you take an aspect 
like logging or locking or .., write it once, and apply it to specified 
methods of a class.

Example:

aspect LockingAspect {
   void onEnter() {
     ..lock...
   }
   void onLeave() {
     ..unlock..
   }
}

class Foo {
   void fooBar() : LockingAspect {
   }
}

so onEnter is called when fooBar is called, and onLeave is called when it 
returns (and when an exception is throw).

The above is an idea of the syntax that could be used. In addition I am no 
expert on aspect oriented programming and what I have said above is off 
the top of my head.

As you have discovered it's impossible to implement without a preprocessor 
(or compiler support)

Regan

On Sat, 31 Jul 2004 02:00:26 +0200, h3r3tic <h3r3tic dev.null> wrote:
 Ok, call me insane, but I think it would be really nice to have 
 something along these lines supported in D:

 functype traced
 {
      version (debug)
      {
          in {
              // writefln("Entering ", name);
          }
 		
          out {
              // writefln("Exiting ", name);
          }

          except(Object x) {
              writefln("Exception caught in function ", name);
          }
      }
 }


 And then write:

 void foo() traced
 {
 }


 It wouldn't be that hard thing to do, although the parsing rules for 
 functions would have to be altered to support the additional type 
 specifier. The in and out blocks could actually be added to the 
 function's in and out blocks and if any except block was defined in the 
 functype, the function could be wrapped in a try block and then the 
 exceptions could be handled.
 name would be replaced by the function name, in this one case, "foo".
 Moreover, the functype thingie might also take some optional parameters.

 Probably not a 1.0 thing though ;) but I can see no other way to have 
 nice traces of where an error has occured (unless we get nice stack 
 traces) and this could prove to be useful after all. If I don't get a 
 similar feature or stack traces that can nicely print a function call 
 tree, I'm writing a preprocessor for D. There are so many cool things 
 that can be done with it that sometimes the lack of a preprocessor in D 
 is a real hit...
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 01 2004
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Regan Heath wrote:

 This idea is close to the 'aspect oriented programming' idea, or rather 
 with a little extending could be used for aspect oriented programming.
 
 The idea behind aspect oriented programming is that you take an aspect 
 like logging or locking or .., write it once, and apply it to specified 
 methods of a class.
 
 Example:
 
 aspect LockingAspect {
   void onEnter() {
     ..lock...
   }
   void onLeave() {
     ..unlock..
   }
 }
 
 class Foo {
   void fooBar() : LockingAspect {
   }
 }
 
 so onEnter is called when fooBar is called, and onLeave is called when 
 it returns (and when an exception is throw).
 
 The above is an idea of the syntax that could be used. In addition I am 
 no expert on aspect oriented programming and what I have said above is 
 off the top of my head.
 
 As you have discovered it's impossible to implement without a 
 preprocessor (or compiler support)
From what I can gather, aspects are a bit more general. AspectJ implements them as a sort of subset of the Lisp macro concept: the programmer writes little bits of code (which form a unit called an aspect) which can be attached to classes, which attaches code before/after/within methods that match certain criteria, and so forth. (for instance, your LockingAspect would instead be applied to a whole class, and could automatically perform the proper locking actions before and after any public method call, when an exception is thrown, and so forth) I'm no expert myself, mind you, so a grain (or truckload) of salt is a good idea. ;) -- andy
Aug 01 2004
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Andy Friesen wrote:
 
  From what I can gather, aspects are a bit more general.  AspectJ 
 implements them as a sort of subset of the Lisp macro concept: the 
 programmer writes little bits of code (which form a unit called an 
 aspect) which can be attached to classes, which attaches code 
 before/after/within methods that match certain criteria, and so forth.
 
 (for instance, your LockingAspect would instead be applied to a whole 
 class, and could automatically perform the proper locking actions before 
 and after any public method call, when an exception is thrown, and so 
 forth)
I think it could work either way. But AOP is traditionally applied entirely separately from the original class (which is why it's so powerful). Like say you have this structure: void foo() {} void bar() { foo(); } You could use AOP to define code that should be run before and after foo is called without ever modifying the code for foo. A very powerful technique and one which I think has tremendous potential to ease maintenance and confuse the heck out of people trying to decipher code :)
 I'm no expert myself, mind you, so a grain (or truckload) of salt is a 
 good idea. ;)
Same here. I've read papers on it but never used it, as I don't do much programming in Java (and AspectC++ is kinda half-baked). Sean
Aug 01 2004
next sibling parent reply h3r3tic <h3r3tic dev.null> writes:
Sean Kelly wrote:
 You could use AOP to define code that should be run before and after foo 
 is called without ever modifying the code for foo.  A very powerful 
 technique and one which I think has tremendous potential to ease 
 maintenance and confuse the heck out of people trying to decipher code :)
Yeah, and that's what I'm worried about. That some very *nice* bugs might result from this. Not knowing about an aspect messing with you somewhere around could be a real PITA. That's why I'd rather specify explicitly that an aspect is being used somewhere with the notation void foo() : bar, where bar is the aspect. This would probably be seen well by people who are concerned by the performance of their code. Moreover, not using the wildcard - style of function matching (the explicit way) would surely be easier to implement. Yet another D's design choice is met :) And no, I wouldn't like writing: debug auto Tracer T = new Tracer("foo()", bar); for every function that I wanted use the 'aspect'. Imagine changing the Tracer's interface after you've made a hundred functions use it. Hell... and one of the reasons AOP has emerged in the first way. IMO, it wouldn't be that bad to add these ': traced' or whatever else to the function and never care about it. this.not an expert this.only read papers ;)
Aug 01 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
On Mon, 02 Aug 2004 02:25:05 +0200, h3r3tic <h3r3tic dev.null> wrote:
 Sean Kelly wrote:
 You could use AOP to define code that should be run before and after 
 foo is called without ever modifying the code for foo.  A very powerful 
 technique and one which I think has tremendous potential to ease 
 maintenance and confuse the heck out of people trying to decipher code 
 :)
Yeah, and that's what I'm worried about. That some very *nice* bugs might result from this. Not knowing about an aspect messing with you somewhere around could be a real PITA. That's why I'd rather specify explicitly that an aspect is being used somewhere with the notation void foo() : bar, where bar is the aspect. This would probably be seen well by people who are concerned by the performance of their code. Moreover, not using the wildcard - style of function matching (the explicit way) would surely be easier to implement. Yet another D's design choice is met :)
What do you think of my revised syntax (posted as response to the message this is also a response to).
 And no, I wouldn't like writing:
 debug auto Tracer T = new Tracer("foo()", bar);

 for every function that I wanted use the 'aspect'. Imagine changing the 
 Tracer's interface after you've made a hundred functions use it. Hell... 
 and one of the reasons AOP has emerged in the first way. IMO, it 
 wouldn't be that bad to add these ': traced' or whatever else to the 
 function and never care about it.

 this.not an expert
 this.only read papers ;)
:) Regan. -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 01 2004
parent h3r3tic <h3r3tic dev.null> writes:
Regan Heath wrote:
 What do you think of my revised syntax (posted as response to the 
 message this is also a response to).
I llllove it :)
Aug 01 2004
prev sibling parent Regan Heath <regan netwin.co.nz> writes:
On Sun, 01 Aug 2004 17:09:15 -0700, Sean Kelly <sean f4.ca> wrote:
 Andy Friesen wrote:
  From what I can gather, aspects are a bit more general.  AspectJ 
 implements them as a sort of subset of the Lisp macro concept: the 
 programmer writes little bits of code (which form a unit called an 
 aspect) which can be attached to classes, which attaches code 
 before/after/within methods that match certain criteria, and so forth.

 (for instance, your LockingAspect would instead be applied to a whole 
 class, and could automatically perform the proper locking actions 
 before and after any public method call, when an exception is thrown, 
 and so forth)
I think it could work either way. But AOP is traditionally applied entirely separately from the original class (which is why it's so powerful). Like say you have this structure: void foo() {} void bar() { foo(); } You could use AOP to define code that should be run before and after foo is called without ever modifying the code for foo. A very powerful technique and one which I think has tremendous potential to ease maintenance and confuse the heck out of people trying to decipher code :)
Doh! I completely forgot about that particular aspect (pun intended) or it. To revise my syntax... aspect Locking { onBefore() {..etc..} onAfter() {..etc..} onProceedQuery() {..etc..} onException() {..etc..} onFincally() {..etc..} } aspect Logging { onBefore() {..etc..} onAfter() {..etc..} onProceedQuery() {..etc..} onException() {..etc..} onFincally() {..etc..} } class originalFoo { void Foo() {..etc..} void Bar() {..etc..} } class derivedFoo : originalFoo { void Foo() : Locking; //apply Locking, keep base class function void Bar() : Logging { //apply logging, override base class function super.Bar(); ..etc.. } }
 I'm no expert myself, mind you, so a grain (or truckload) of salt is a 
 good idea. ;)
Same here. I've read papers on it but never used it, as I don't do much programming in Java (and AspectC++ is kinda half-baked). Sean
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 01 2004
prev sibling parent Regan Heath <regan netwin.co.nz> writes:
On Sun, 01 Aug 2004 16:34:02 -0700, Andy Friesen <andy ikagames.com> wrote:

 Regan Heath wrote:

 This idea is close to the 'aspect oriented programming' idea, or rather 
 with a little extending could be used for aspect oriented programming.

 The idea behind aspect oriented programming is that you take an aspect 
 like logging or locking or .., write it once, and apply it to specified 
 methods of a class.

 Example:

 aspect LockingAspect {
   void onEnter() {
     ..lock...
   }
   void onLeave() {
     ..unlock..
   }
 }

 class Foo {
   void fooBar() : LockingAspect {
   }
 }

 so onEnter is called when fooBar is called, and onLeave is called when 
 it returns (and when an exception is throw).

 The above is an idea of the syntax that could be used. In addition I am 
 no expert on aspect oriented programming and what I have said above is 
 off the top of my head.

 As you have discovered it's impossible to implement without a 
 preprocessor (or compiler support)
From what I can gather, aspects are a bit more general. AspectJ implements them as a sort of subset of the Lisp macro concept: the programmer writes little bits of code (which form a unit called an aspect) which can be attached to classes, which attaches code before/after/within methods that match certain criteria, and so forth. (for instance, your LockingAspect would instead be applied to a whole class, and could automatically perform the proper locking actions before and after any public method call, when an exception is thrown, and so forth) I'm no expert myself, mind you, so a grain (or truckload) of salt is a good idea. ;)
The only knowledge I have of it came from "Christopher Diggins" article in the August 2004 DrDobbs Journal. In it he described a thing called a 'Point Cut' which defined the methods to apply the Aspect to. I think being able to apply certain Aspects to specified methods give awesome flexibility eg. aspect Locking { } aspect Logging { } cass Foo { void Bar() : Locking { } void Baz() : Logging { } } so both aspects are used, Locking for Bar and Logging for Baz. In fact the more I look at this syntax the more I like it. Regan. -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 01 2004
prev sibling parent reply Nick <Nick_member pathlink.com> writes:
Traces, aspects and what have you... I may be very wrong here, but as I see it
the only proposed use for all this is to have a special event happen at the
beginning and at the end of function calls. Isn't this a lot of structural and
linguistic baggage to add just to accomplish this single purpose?

I liked Walters proposal of using an auto class. With for example a variadic
constructor you could do something like










Since most of the other proposed methods require you to mark functions in one
way or another anyway, I don't see this as too much to type.

I've done something similar in C++ once, coupled with an independant class which
kept track of the function "stack" (it didn't touch the actual stack) this way.
Also all exception classes I used would capture a local copy of the this stack
and use this to produce an error message of the form

main
foo1
foo2 <-- caught here
foo3
foo4 <-- thrown here

Also, more importantly, the "stack" class also caught uncaught exceptions like a
GPF (this was Windows) and displayed a trace. I swear this must have reduced my
bug hunting time by at least a factor of 10 ;-)

Doing this in D would effectively require fixing up the Exception class though,
so it would have to be part of phobos.

Nick

In article <opsb2r21w95a2sq9 digitalmars.com>, Regan Heath says...
This idea is close to the 'aspect oriented programming' idea, or rather 
with a little extending could be used for aspect oriented programming.

The idea behind aspect oriented programming is that you take an aspect 
like logging or locking or .., write it once, and apply it to specified 
methods of a class.

Example:

aspect LockingAspect {
   void onEnter() {
     ..lock...
   }
   void onLeave() {
     ..unlock..
   }
}

class Foo {
   void fooBar() : LockingAspect {
   }
}
Aug 01 2004
parent Regan Heath <regan netwin.co.nz> writes:
On Sun, 1 Aug 2004 23:35:12 +0000 (UTC), Nick <Nick_member pathlink.com> 
wrote:
 Traces, aspects and what have you... I may be very wrong here, but as I 
 see it
 the only proposed use for all this is to have a special event happen at 
 the
 beginning and at the end of function calls. Isn't this a lot of 
 structural and
 linguistic baggage to add just to accomplish this single purpose?
Perhaps.. grab a copy of DrDobbs Journal Aug 2004 and read the article by Christopher Diggins, that's all I have read on the subject, and my impression is that it could be quite useful. Regan
 I liked Walters proposal of using an auto class. With for example a 
 variadic
 constructor you could do something like










 Since most of the other proposed methods require you to mark functions 
 in one
 way or another anyway, I don't see this as too much to type.

 I've done something similar in C++ once, coupled with an independant 
 class which
 kept track of the function "stack" (it didn't touch the actual stack) 
 this way.
 Also all exception classes I used would capture a local copy of the this 
 stack
 and use this to produce an error message of the form

 main
 foo1
 foo2 <-- caught here
 foo3
 foo4 <-- thrown here

 Also, more importantly, the "stack" class also caught uncaught 
 exceptions like a
 GPF (this was Windows) and displayed a trace. I swear this must have 
 reduced my
 bug hunting time by at least a factor of 10 ;-)

 Doing this in D would effectively require fixing up the Exception class 
 though,
 so it would have to be part of phobos.

 Nick

 In article <opsb2r21w95a2sq9 digitalmars.com>, Regan Heath says...
 This idea is close to the 'aspect oriented programming' idea, or rather
 with a little extending could be used for aspect oriented programming.

 The idea behind aspect oriented programming is that you take an aspect
 like logging or locking or .., write it once, and apply it to specified
 methods of a class.

 Example:

 aspect LockingAspect {
   void onEnter() {
     ..lock...
   }
   void onLeave() {
     ..unlock..
   }
 }

 class Foo {
   void fooBar() : LockingAspect {
   }
 }
-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 01 2004
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
h3r3tic wrote:

 Ok, call me insane, but I think it would be really nice to have 
 something along these lines supported in D:
 
 functype traced
 {
     version (debug)
<snip> That would be no good. debug is a keyword. Which you should be using for debugging code, not version. Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Aug 02 2004
parent h3r3tic <h3r3tic dev.null> writes:
Stewart Gordon wrote:
 h3r3tic wrote:
 
 functype traced
 {
     version (debug)
<snip> That would be no good. debug is a keyword. Which you should be using for debugging code, not version.
that was not the point !(g)... yea, it should've been debug { ... }
Aug 02 2004