Ian said:
But what advantages do they offer over the alternative non-intrusive
approaches?
Among the advantages of the intrinsic call/return pattern are: simplicity,
clarity, uniformity, localization of functionality, access to intrinsic
state, inheritability, etc. I am, of course, making some assumptions about
how it might be implemented.
I can't see any and the lack of access to the member's parameters is a big
disadvantage.
I don't see these bracketing functions as call specific. They would work at
the level of the object as a whole. Since I've never actually had them to
work with, and have only been aware of the concept for a day, it's hard for
me to assess their full potential.
I can't see any relationship between call() and return() and Java. They
are two solutions in two completely unrelated problems spaces.
http://www.gotw.ca/publications/c_family_interview.htm
"Q: Did you ever add features that your users didn't appreciate as much as
you did, and then have to deprecate or remove them later? What did you
learn from the experience?
[...]
Stroustrup: When I designed C with Classes and C++, I was very keen on the
idea that a class defined the environment in which the code of its member
functions operate (I still am). This led to the notion of constructors that
establish that environment (invariant) and acquire the resources needed.
Destructors reverse that process (releasing resources). These ideas are at
the root of the design of exceptions and resource management. For example,
see the new Appendix E: "Standard-Library Exception Safety" of The C++
Programming Language.[3] That appendix can be downloaded from my home
pages.[4]
Based on that line of thinking, C with Classes also allowed you to define a
call() function that was called before entry into a member function and a
return() function that was called after exit from a member function. The
call()/return() mechanism was meant to allow a programmer to manage
resources needed for an individual member function invocation. This allowed
me to implement monitors for the first task library. A task's call()
grabbed a lock and its matching return() released the lock. The idea came
partly from Lisp's :before and :after methods. However, the notion wasn't
perfectly general -- for example, you couldn't access arguments for a
member function call from call() [So what?]. Worse, I completely failed to
convince people of the usefulness of this notion, so I removed call() and
return() when I defined C++."
http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html [*]
"§17.1 Locks
The Java programming language provides multiple mechanisms for communicating
between threads. The most basic of these methods is synchronization, which
is implemented using monitors. Each object in Java is associated with a
monitor, which a thread can lock or unlock. Only one thread at a time may
hold a lock on a monitor. Any other threads attempting to lock that monitor
are blocked until they can obtain a lock on that monitor. A thread t may
lock a particular monitor multiple times; each unlock reverses the effect
of one lock operation."
I am aware that one can synchronize on individual Java methods, which
appears contrary to the idea of simple before/after bracketing on a class
instance.
"§8.4.3.6 synchronized Methods
A synchronized method acquires a monitor (§17.1) before it executes. For a
class (static) method, the monitor associated with the Class object for the
method's class is used. For an instance method, the monitor associated with
this (the object for which the method was invoked) is used."
Bear in mind, however, that a method in Java is actually and instance of
java.lang.reflect.Method. At any rate, the same kind of selectivity could
be accomplished in C++ with call/return through multiple inheritance. Or
through a language extension such as support for a /synchronized/ keyword.
[*]Everybody who contributes text to the C++ Standard should read this book.
Not for the technical ideas, but as an example of an alternative style of
presentation.