From: Hector Santos on
Joseph M. Newcomer wrote:

>> In general, IPC DESIGN is independent of language, although some
>> language lend themselves to IPC designs.
> ****
> IPC == Inter-Process Communication. I see no IPC here;


Gawd, I knew you were going to say that!!

To communications people, The "I" can means both INTER and INTRA!

You are missing the boat here since this is so fundamental and to get
lost with statements that its a C hack, well, it really inviting yet
another worthless debate with you. Because of that I "try" will
refrain from further comment.

--
HLS
From: Hector Santos on
Joseph M. Newcomer wrote:

> Again, you are dragging IPC into a discussion where IPC was not involved. You can do
> callbacks such as event sinks without exposing the ugliness of the raw callback mechanism.


Ok, lets try to get this debate civilly. I don't care for history so
please try to refrain from personal opinions there, i.e. callback is a
C hack.

What do you consider is a raw callback mechanism?

Now, in the previous message, you stated that if it didn't provide a
user-define value, then YES, I will agree that a callback mechanism
that doesn't take into account:

1) Rentrancy
2) Provide for user-defined object/data access,

then yes, it is a poor implementation. I agree, and when dealing with
3rd party software with callback logic lacking the above, especially
#2, then absolutely, its problematic.

But that is an implementation issue, and not a language or "C Hack"
issue. You can say that the C++ layer provide a cleaner interface,
and I agree, but I will also note that these are generally based on a
lower level callback abstraction. In fact, I seem to recall dealing
with 3rd party software where it lacked a user-defined value and using
a C++ wrapper help resolved that by making the callback static in the
class, and combining it with TLS. I forget that project, but I do
recall going through those motions.

So it depends on what kind of design you are referring too. Writing
an C++ implementation is excellent and most of our stuff is written in
this way using interfaces. But I guess I have to wonder why we use
C++ in general. I think it because of its

- natural scoping capabilities,
- constructors and destructors,
- polymorphisms and interface.

The virtual interface, a large part, but not the only part.

Keep in mind you can duplicate all the above within pure C if you
provide the library code to do so.

--
HLS
From: Joseph M. Newcomer on
See below...
On Sat, 13 Feb 2010 18:44:35 -0500, Hector Santos <sant9442(a)nospam.gmail.com> wrote:

>Joseph M. Newcomer wrote:
>
>> Again, you are dragging IPC into a discussion where IPC was not involved. You can do
>> callbacks such as event sinks without exposing the ugliness of the raw callback mechanism.
>
>
>Ok, lets try to get this debate civilly. I don't care for history so
>please try to refrain from personal opinions there, i.e. callback is a
>C hack.
****
Actually, a callback is an assembly code hack, translated into C. This is not an opinion,
it is a statement of fact. Callbacks at this level exist because the languages were
unable to provide a suitable abstraction, so instead of some clean mechanism, the old
let's-use-a-pointer technique was recast from assembler to C. It is a hack in that it is
simply a translation of a machine-level concept directly into a high-level language.

OTOH, the notion of virtual methods as a means of invoking operations is consistent with
the linguistic design of C++, and although it is done *exactly* by using a pointer to
redirect the call, it is done in a framework that is semantically consistent with a
high-level abstraction.
****
>
>What do you consider is a raw callback mechanism?
*****
call [eax]

substitute other register names, it is isomorphic to renaming. Expressed in C, it is
implemented by passing in a function pointer as a parameter to a call, with the purpose
that the specified function is called when there is a desire to invoke some operation. It
is limited to a single function in general.
*****
>
>Now, in the previous message, you stated that if it didn't provide a
>user-define value, then YES, I will agree that a callback mechanism
>that doesn't take into account:
>
> 1) Rentrancy
> 2) Provide for user-defined object/data access,
>
>then yes, it is a poor implementation. I agree, and when dealing with
>3rd party software with callback logic lacking the above, especially
>#2, then absolutely, its problematic.
****
Sadly, most 3rd party software fails in both the above. The Windows API has far too many
callback-style APIs that fail in the same way, including, inexcusably, some that were
added in either 2000 or XP, when the issues were well-known, but totally ignored.
****
>
>But that is an implementation issue, and not a language or "C Hack"
>issue. You can say that the C++ layer provide a cleaner interface,
>and I agree, but I will also note that these are generally based on a
>lower level callback abstraction. In fact, I seem to recall dealing
>with 3rd party software where it lacked a user-defined value and using
>a C++ wrapper help resolved that by making the callback static in the
>class, and combining it with TLS. I forget that project, but I do
>recall going through those motions.
*****
The issue is in confusing an interface that works directly and "in-your-face" with raw
function pointers, and one which uses the syntactic features of the language (like virtual
methods, a first-class concept) to disguise the implementation details and provide for a
degree of cleanliness and elegance. For example, compare try/catch/throw or _try/_except
to setjmp/longjmp as mechanisms. All are stack unwinders. But setjmp/longjmp is an
inelegant kludge compared to _try/_except, and neither will work in C++ because of the
need to invoke destructors as the stack unwinds.

Note that in what is now my 47th year as a programmer, I have used callbacks under all
kinds of conditions; I have grown to despise it as a way of life, particularly because it
is so easily misused and abused. I have written stack unwinders, I have implemented
try/catch mechanisms, I have implemented event notification systems, interrupt handlers,
and pretty much everything that is possible to do with pointers-to-functions. And I
prefer to use the C++ virtual function model. Note that the message map is actually a
poor kludge; in a sane world, they would have been virtual methods, but in 16-bit windows
the vtables would have gotten too large and the message map was invented as a more compact
representation of the abstraction. It might have even worked well if they had gotten just
a few more details right, such as always accepting the parameters passed to the superclass
(this is a failure of design and implementation of a callback mechanism!). So I've seen
all possible mistakes, and even made quite a few of them, particularly in my first ten
years or so of programming.

So I recognize the difference between a low-level hack and a methodology that is part of a
linguistically consistent framework.

I was shocked when Ada did not allow the passing of function pointers, wondering how it
was possible to specify callbacks. Then I realized the language had alternative
mechanisms that eliminated most of the need for user-specified callback functions
(internally, the generated code performed callbacks, but you didn't have to see that).
This was in the late 1970s, and since then I have realized that the raw callback is just a
continuing hack to get an effect that should be achievable in other ways. The C++ virtual
method (or C#, or Java virtual method) is one of these mechanisms. And there are those
who will argue that even virtual methods are a hack, and that embedding, using interfaces,
is the only way to go (e.g., COM, and the new Google GO language, which I have seen only
little bits of). Ultimately, we want to get away from the decades-old concepts (like the
computed GOTO) that were done to allow high-level programmers create constructs that
compiled into efficient code at the low level, and go for clean abstractions (which most
decent compilers can compile into incredibly good code at the low level, with no effort on
the part of the programmer. I used to say that in a good language with a good compiler,
you can write six levels of abstraction that compile into half an instruction. I've
worked with good languages and good compilers, and have done this, repeatedly).

It's too easy to get captivated by the implementation and forget that the implementation
details are best left to automated mechanisms. Compilers are really good at this sort of
grubby detail. At the lowest level, the implementation might be the instruction
call [eax]
but you should never have to think of this at the coding level. The construct
function(args)
where 'function' is actually a pointer is too close to the call [eax] to be really
comfortable.

Fortunately, the tools we have for MFC eliminate many of the visible details of how
message maps are actually dispatched. At the lowest level, it really is
call [eax]
(in fact, if you single-step through the AfxWndProc assembly code far enough, this is what
you will see, isomorphic to renaming of the register). But as an MFC programming, I have
a very high-level concept: add an event handler. I don't need to see the details of the
implementation. It just works. Well, sort-of-works, but I've already described the
problems there. Virtual methods, if you accept derivation as the way of creating new
classes, do the same job.
****
>
>So it depends on what kind of design you are referring too. Writing
>an C++ implementation is excellent and most of our stuff is written in
>this way using interfaces. But I guess I have to wonder why we use
>C++ in general. I think it because of its
>
> - natural scoping capabilities,
> - constructors and destructors,
> - polymorphisms and interface.
>
>The virtual interface, a large part, but not the only part.
>
>Keep in mind you can duplicate all the above within pure C if you
>provide the library code to do so.
****
And you can write in assembler, too, but it doesn't mean it is a good thing most of the
time.

I'm working on a course in assembly code, because there are still people who need to work
with it (yes, I was surprised, but the uses are legitimate). One of the surprises was the
number of people who need to write really tight, high-performance SIMD code (apparently
the x64 intrinsics don't produce particularly good code when they are used for this). But
it doesn't mean that people should write apps in assembler.

If my customer base accepted it, I'd be writing in C# or WPF, but they don't want this. In
fact, are opposed to it (I'm not sure I follow the reasoning, but they write the checks,
and I want to take their money). So I write in C++, and in a few cases in C (and I just
finished a library in C, several thousand lines of code, in which callbacks form a
particularly important part of the functionality. But I'd rather have done it in C++ and
just supplied a pure virtual method. You would not BELIEVE what I saw done there when I
got the library; it was a particularly ugly callback, well, I can't really call it
"design", and "kludge" gives it too much dignity, but as redesigned, it is essentially a
virtual method mechanism and therefore intellectually manageable, as well as handling a
ton of problems the old mechanism simply ignored). So I still use them, but they *should*
be avoided as a way of life in most coding. I nearly made all the complexity of the
earlier kludge disappear in the new design, which took major rework to get complete and
consistent. Doing a callback *right* isn't easy, and most people, I have found, take the
easy solution. If you assume that you should avoid them, then you use them only when
necessary, and ideally wrap enough syntactic sugar around them to make them go down easily
(e.g., virtual methods in C++).
joe
*****
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Hector Santos on
Man, reading you, one has to wonder why the world has blown up yet or
gotten this far. Everything was wrong, badly designed, hacked and no
one ever used it right or differently. Its all one way with you. Just
consider your inconsequential historical callback note had nothing to
do with the OP issue or question, nor contributed to the problem. I'm
sure until the code is posted, you would not exclude it as a
possibility. I say its mostly likely unrelated.

Anyway, it would interesting to hear your critic on the design faults
of the human brain! :)

--

Joseph M. Newcomer wrote:

> See below...
> On Sat, 13 Feb 2010 18:44:35 -0500, Hector Santos <sant9442(a)nospam.gmail.com> wrote:
>
>> Joseph M. Newcomer wrote:
>>
>>> Again, you are dragging IPC into a discussion where IPC was not involved. You can do
>>> callbacks such as event sinks without exposing the ugliness of the raw callback mechanism.
>>
>> Ok, lets try to get this debate civilly. I don't care for history so
>> please try to refrain from personal opinions there, i.e. callback is a
>> C hack.
> ****
> Actually, a callback is an assembly code hack, translated into C. This is not an opinion,
> it is a statement of fact. Callbacks at this level exist because the languages were
> unable to provide a suitable abstraction, so instead of some clean mechanism, the old
> let's-use-a-pointer technique was recast from assembler to C. It is a hack in that it is
> simply a translation of a machine-level concept directly into a high-level language.
>
> OTOH, the notion of virtual methods as a means of invoking operations is consistent with
> the linguistic design of C++, and although it is done *exactly* by using a pointer to
> redirect the call, it is done in a framework that is semantically consistent with a
> high-level abstraction.
> ****
>> What do you consider is a raw callback mechanism?
> *****
> call [eax]
>
> substitute other register names, it is isomorphic to renaming. Expressed in C, it is
> implemented by passing in a function pointer as a parameter to a call, with the purpose
> that the specified function is called when there is a desire to invoke some operation. It
> is limited to a single function in general.
> *****
>> Now, in the previous message, you stated that if it didn't provide a
>> user-define value, then YES, I will agree that a callback mechanism
>> that doesn't take into account:
>>
>> 1) Rentrancy
>> 2) Provide for user-defined object/data access,
>>
>> then yes, it is a poor implementation. I agree, and when dealing with
>> 3rd party software with callback logic lacking the above, especially
>> #2, then absolutely, its problematic.
> ****
> Sadly, most 3rd party software fails in both the above. The Windows API has far too many
> callback-style APIs that fail in the same way, including, inexcusably, some that were
> added in either 2000 or XP, when the issues were well-known, but totally ignored.
> ****
>> But that is an implementation issue, and not a language or "C Hack"
>> issue. You can say that the C++ layer provide a cleaner interface,
>> and I agree, but I will also note that these are generally based on a
>> lower level callback abstraction. In fact, I seem to recall dealing
>> with 3rd party software where it lacked a user-defined value and using
>> a C++ wrapper help resolved that by making the callback static in the
>> class, and combining it with TLS. I forget that project, but I do
>> recall going through those motions.
> *****
> The issue is in confusing an interface that works directly and "in-your-face" with raw
> function pointers, and one which uses the syntactic features of the language (like virtual
> methods, a first-class concept) to disguise the implementation details and provide for a
> degree of cleanliness and elegance. For example, compare try/catch/throw or _try/_except
> to setjmp/longjmp as mechanisms. All are stack unwinders. But setjmp/longjmp is an
> inelegant kludge compared to _try/_except, and neither will work in C++ because of the
> need to invoke destructors as the stack unwinds.
>
> Note that in what is now my 47th year as a programmer, I have used callbacks under all
> kinds of conditions; I have grown to despise it as a way of life, particularly because it
> is so easily misused and abused. I have written stack unwinders, I have implemented
> try/catch mechanisms, I have implemented event notification systems, interrupt handlers,
> and pretty much everything that is possible to do with pointers-to-functions. And I
> prefer to use the C++ virtual function model. Note that the message map is actually a
> poor kludge; in a sane world, they would have been virtual methods, but in 16-bit windows
> the vtables would have gotten too large and the message map was invented as a more compact
> representation of the abstraction. It might have even worked well if they had gotten just
> a few more details right, such as always accepting the parameters passed to the superclass
> (this is a failure of design and implementation of a callback mechanism!). So I've seen
> all possible mistakes, and even made quite a few of them, particularly in my first ten
> years or so of programming.
>
> So I recognize the difference between a low-level hack and a methodology that is part of a
> linguistically consistent framework.
>
> I was shocked when Ada did not allow the passing of function pointers, wondering how it
> was possible to specify callbacks. Then I realized the language had alternative
> mechanisms that eliminated most of the need for user-specified callback functions
> (internally, the generated code performed callbacks, but you didn't have to see that).
> This was in the late 1970s, and since then I have realized that the raw callback is just a
> continuing hack to get an effect that should be achievable in other ways. The C++ virtual
> method (or C#, or Java virtual method) is one of these mechanisms. And there are those
> who will argue that even virtual methods are a hack, and that embedding, using interfaces,
> is the only way to go (e.g., COM, and the new Google GO language, which I have seen only
> little bits of). Ultimately, we want to get away from the decades-old concepts (like the
> computed GOTO) that were done to allow high-level programmers create constructs that
> compiled into efficient code at the low level, and go for clean abstractions (which most
> decent compilers can compile into incredibly good code at the low level, with no effort on
> the part of the programmer. I used to say that in a good language with a good compiler,
> you can write six levels of abstraction that compile into half an instruction. I've
> worked with good languages and good compilers, and have done this, repeatedly).
>
> It's too easy to get captivated by the implementation and forget that the implementation
> details are best left to automated mechanisms. Compilers are really good at this sort of
> grubby detail. At the lowest level, the implementation might be the instruction
> call [eax]
> but you should never have to think of this at the coding level. The construct
> function(args)
> where 'function' is actually a pointer is too close to the call [eax] to be really
> comfortable.
>
> Fortunately, the tools we have for MFC eliminate many of the visible details of how
> message maps are actually dispatched. At the lowest level, it really is
> call [eax]
> (in fact, if you single-step through the AfxWndProc assembly code far enough, this is what
> you will see, isomorphic to renaming of the register). But as an MFC programming, I have
> a very high-level concept: add an event handler. I don't need to see the details of the
> implementation. It just works. Well, sort-of-works, but I've already described the
> problems there. Virtual methods, if you accept derivation as the way of creating new
> classes, do the same job.
> ****
>> So it depends on what kind of design you are referring too. Writing
>> an C++ implementation is excellent and most of our stuff is written in
>> this way using interfaces. But I guess I have to wonder why we use
>> C++ in general. I think it because of its
>>
>> - natural scoping capabilities,
>> - constructors and destructors,
>> - polymorphisms and interface.
>>
>> The virtual interface, a large part, but not the only part.
>>
>> Keep in mind you can duplicate all the above within pure C if you
>> provide the library code to do so.
> ****
> And you can write in assembler, too, but it doesn't mean it is a good thing most of the
> time.
>
> I'm working on a course in assembly code, because there are still people who need to work
> with it (yes, I was surprised, but the uses are legitimate). One of the surprises was the
> number of people who need to write really tight, high-performance SIMD code (apparently
> the x64 intrinsics don't produce particularly good code when they are used for this). But
> it doesn't mean that people should write apps in assembler.
>
> If my customer base accepted it, I'd be writing in C# or WPF, but they don't want this. In
> fact, are opposed to it (I'm not sure I follow the reasoning, but they write the checks,
> and I want to take their money). So I write in C++, and in a few cases in C (and I just
> finished a library in C, several thousand lines of code, in which callbacks form a
> particularly important part of the functionality. But I'd rather have done it in C++ and
> just supplied a pure virtual method. You would not BELIEVE what I saw done there when I
> got the library; it was a particularly ugly callback, well, I can't really call it
> "design", and "kludge" gives it too much dignity, but as redesigned, it is essentially a
> virtual method mechanism and therefore intellectually manageable, as well as handling a
> ton of problems the old mechanism simply ignored). So I still use them, but they *should*
> be avoided as a way of life in most coding. I nearly made all the complexity of the
> earlier kludge disappear in the new design, which took major rework to get complete and
> consistent. Doing a callback *right* isn't easy, and most people, I have found, take the
> easy solution. If you assume that you should avoid them, then you use them only when
> necessary, and ideally wrap enough syntactic sugar around them to make them go down easily
> (e.g., virtual methods in C++).
> joe
> *****
> Joseph M. Newcomer [MVP]
> email: newcomer(a)flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm



--
HLS
From: Joseph M. Newcomer on

On Sat, 13 Feb 2010 23:23:52 -0500, Hector Santos <sant9442(a)nospam.gmail.com> wrote:

>
>Man, reading you, one has to wonder why the world has blown up yet or
> gotten this far. Everything was wrong, badly designed, hacked and no
>one ever used it right or differently. Its all one way with you. Just
>consider your inconsequential historical callback note had nothing to
>do with the OP issue or question, nor contributed to the problem. I'm
>sure until the code is posted, you would not exclude it as a
>possibility. I say its mostly likely unrelated.
****
What continues to amaze me is that ideas we knew were bad in 1970 keep getting re-invented
by another generation who doesn't understand why they were abandoned. We worked for
decades to improve the quality of programming, and here we are, in 2010, where the
state-of-the-art is stuck essentially at C, and the C fanatics wonder why we say there are
problems. There are problems because nobody actually pays attention to the past, looks at
past successes or failures, but just start, from scratch, reinventing the same bad ideas
over and over and over again. We just re-invented timesharing, which we realized by the
early 70s was a Bad Idea. Now we call it "cloud computing". Duh. For all the same
reasons that timesharing was bad in the 1970s, cloud computing is bad. So if I seem
overly cynical, remember that this is not the FIRST time I've seen bad ideas re-invented;
I've been around long enough to see most of them re-invented two or three times.
Approximately a generation apart.

Unfortunately, I'm not the kind of old codger who longs for the "good old days". The best
part of the good old days is that they are in the past, and we have grown beyond them. And
then someone comes along and tells me that the good old days were the best time, and the
ideas we tried and abandoned are essential to good software. I am skeptical of this.

Why aren't we programming in functional languages? Why do we even still have compilers
that run as separate preprocessors to execution? (Seriously: trace-based compilation
systems exist, and run, and are used every day, and here we sit with C and C++ and VB and
C# compilers, stuck in the punched-card model that I had abandoned by 1969, forty years
ago. C/C++ used to have a working edit-and-continue system until it was broken, and while
C# and VB make such a system trivial, they never seem to have had it. Duh. We've gone
backward since VS6, instead of forward.

Callbacks were a bad idea; we knew better how to handle this in the early 1970s. Look at
LISP closures, for example, and the large number of languages that managed to implement
closures by the 1980s. Mutex-style synchronization was dead by the end of the 1980s, but
not one of the good implementations of interthread synchronization made it to
commonly-used languages. So we see deadlock problems. Callbacks, by the way, introduce
problems in reasoning about program logic which makes reasoning about deadlock causes much
harder, so my observations are *not* irrelevant to the OP. I've been doing multithreading
since 1975 as a way of life, and was even doing multithreading back in 1968. And I
learned that explicit locking is usually a mistake. It is a hack to solve a problem that
should be solved by architecture, and the low-level lock we are familiar with, although it
needs to exist, should be completely invisible to the programmer (example: putting
elements in queues requires a lock at the lowest level, but I should never see that or
have to reason about it). People who worried about these issues have won Turing awards
(the computer profession's equivalent of the Nobel Prize) yet not a single one of their
ideas exists in our programming languages. The "synchronize" capabilities of Java and C#
are deeply flawed (a friend of mine just got his PhD for building a program that finds
synchronization errors in Java, and his comment is, "Everyone gets threading wrong all the
time. Start with that as your premise" and has the experience of examining, with his
program, over half a million lines of Java written by some of the best Java multithreading
experts to demonstrate that even they made serious errors).

So yes, we are, for all practical purposes, programming largely using 1970 technology,
except when we are using 1960 technology. In the 1980s, I was one of the founding
scientists of the Software Engineering Institute, and was examining the best-of-the-best
technology so we could figure out how to get it into the mainstream. The mainstream
didn't want it; they were content with 1960s technology because they were comfortable with
it. Learning new stuff, and better ways to do things, was not an acceptable agenda. I
left the SEI when I realized that (a) it had nothing to do with the actual *Engineering*
of software, but was concerned with the *management* of the process and (b) industry
didn't want to change what it was doing for any reason, no matter how cost-effective it
might be in the long run.

I really don't want to live in the past, and when I complain that yet again we are
replicating the technology of the 1950s and 1960s, somebody comes along to explain that it
is necessary we do so because there aren't better ways. There have *always* been better
ways.

Consider: JavaScript, the darling of AJAX, is just Simula-67 done badly. The heart of
AJAX, XML, was done better in both 1977 (in a project I was responsible for) and 1981 (in
a PhD dissertation done by a friend, an outgrowth of refining the problems we discovered
in the existing 1977 implementation). DTDs were designed by people who had no experience
designing languages or grammars (just ask any professional language designer. We still
have quite a few around, including a friend of mine who designed the Ada competitor).
Those of us in our 60s, who were there at the leading edges in the 1970s through 1990s,
look around and see that there has been very little progress made in forty years. What we
lament is not that the good old days are gone, but they are, alas, still with us.
joe
****
>
>Anyway, it would interesting to hear your critic on the design faults
>of the human brain! :)
>
>--
>
>Joseph M. Newcomer wrote:
>
>> See below...
>> On Sat, 13 Feb 2010 18:44:35 -0500, Hector Santos <sant9442(a)nospam.gmail.com> wrote:
>>
>>> Joseph M. Newcomer wrote:
>>>
>>>> Again, you are dragging IPC into a discussion where IPC was not involved. You can do
>>>> callbacks such as event sinks without exposing the ugliness of the raw callback mechanism.
>>>
>>> Ok, lets try to get this debate civilly. I don't care for history so
>>> please try to refrain from personal opinions there, i.e. callback is a
>>> C hack.
>> ****
>> Actually, a callback is an assembly code hack, translated into C. This is not an opinion,
>> it is a statement of fact. Callbacks at this level exist because the languages were
>> unable to provide a suitable abstraction, so instead of some clean mechanism, the old
>> let's-use-a-pointer technique was recast from assembler to C. It is a hack in that it is
>> simply a translation of a machine-level concept directly into a high-level language.
>>
>> OTOH, the notion of virtual methods as a means of invoking operations is consistent with
>> the linguistic design of C++, and although it is done *exactly* by using a pointer to
>> redirect the call, it is done in a framework that is semantically consistent with a
>> high-level abstraction.
>> ****
>>> What do you consider is a raw callback mechanism?
>> *****
>> call [eax]
>>
>> substitute other register names, it is isomorphic to renaming. Expressed in C, it is
>> implemented by passing in a function pointer as a parameter to a call, with the purpose
>> that the specified function is called when there is a desire to invoke some operation. It
>> is limited to a single function in general.
>> *****
>>> Now, in the previous message, you stated that if it didn't provide a
>>> user-define value, then YES, I will agree that a callback mechanism
>>> that doesn't take into account:
>>>
>>> 1) Rentrancy
>>> 2) Provide for user-defined object/data access,
>>>
>>> then yes, it is a poor implementation. I agree, and when dealing with
>>> 3rd party software with callback logic lacking the above, especially
>>> #2, then absolutely, its problematic.
>> ****
>> Sadly, most 3rd party software fails in both the above. The Windows API has far too many
>> callback-style APIs that fail in the same way, including, inexcusably, some that were
>> added in either 2000 or XP, when the issues were well-known, but totally ignored.
>> ****
>>> But that is an implementation issue, and not a language or "C Hack"
>>> issue. You can say that the C++ layer provide a cleaner interface,
>>> and I agree, but I will also note that these are generally based on a
>>> lower level callback abstraction. In fact, I seem to recall dealing
>>> with 3rd party software where it lacked a user-defined value and using
>>> a C++ wrapper help resolved that by making the callback static in the
>>> class, and combining it with TLS. I forget that project, but I do
>>> recall going through those motions.
>> *****
>> The issue is in confusing an interface that works directly and "in-your-face" with raw
>> function pointers, and one which uses the syntactic features of the language (like virtual
>> methods, a first-class concept) to disguise the implementation details and provide for a
>> degree of cleanliness and elegance. For example, compare try/catch/throw or _try/_except
>> to setjmp/longjmp as mechanisms. All are stack unwinders. But setjmp/longjmp is an
>> inelegant kludge compared to _try/_except, and neither will work in C++ because of the
>> need to invoke destructors as the stack unwinds.
>>
>> Note that in what is now my 47th year as a programmer, I have used callbacks under all
>> kinds of conditions; I have grown to despise it as a way of life, particularly because it
>> is so easily misused and abused. I have written stack unwinders, I have implemented
>> try/catch mechanisms, I have implemented event notification systems, interrupt handlers,
>> and pretty much everything that is possible to do with pointers-to-functions. And I
>> prefer to use the C++ virtual function model. Note that the message map is actually a
>> poor kludge; in a sane world, they would have been virtual methods, but in 16-bit windows
>> the vtables would have gotten too large and the message map was invented as a more compact
>> representation of the abstraction. It might have even worked well if they had gotten just
>> a few more details right, such as always accepting the parameters passed to the superclass
>> (this is a failure of design and implementation of a callback mechanism!). So I've seen
>> all possible mistakes, and even made quite a few of them, particularly in my first ten
>> years or so of programming.
>>
>> So I recognize the difference between a low-level hack and a methodology that is part of a
>> linguistically consistent framework.
>>
>> I was shocked when Ada did not allow the passing of function pointers, wondering how it
>> was possible to specify callbacks. Then I realized the language had alternative
>> mechanisms that eliminated most of the need for user-specified callback functions
>> (internally, the generated code performed callbacks, but you didn't have to see that).
>> This was in the late 1970s, and since then I have realized that the raw callback is just a
>> continuing hack to get an effect that should be achievable in other ways. The C++ virtual
>> method (or C#, or Java virtual method) is one of these mechanisms. And there are those
>> who will argue that even virtual methods are a hack, and that embedding, using interfaces,
>> is the only way to go (e.g., COM, and the new Google GO language, which I have seen only
>> little bits of). Ultimately, we want to get away from the decades-old concepts (like the
>> computed GOTO) that were done to allow high-level programmers create constructs that
>> compiled into efficient code at the low level, and go for clean abstractions (which most
>> decent compilers can compile into incredibly good code at the low level, with no effort on
>> the part of the programmer. I used to say that in a good language with a good compiler,
>> you can write six levels of abstraction that compile into half an instruction. I've
>> worked with good languages and good compilers, and have done this, repeatedly).
>>
>> It's too easy to get captivated by the implementation and forget that the implementation
>> details are best left to automated mechanisms. Compilers are really good at this sort of
>> grubby detail. At the lowest level, the implementation might be the instruction
>> call [eax]
>> but you should never have to think of this at the coding level. The construct
>> function(args)
>> where 'function' is actually a pointer is too close to the call [eax] to be really
>> comfortable.
>>
>> Fortunately, the tools we have for MFC eliminate many of the visible details of how
>> message maps are actually dispatched. At the lowest level, it really is
>> call [eax]
>> (in fact, if you single-step through the AfxWndProc assembly code far enough, this is what
>> you will see, isomorphic to renaming of the register). But as an MFC programming, I have
>> a very high-level concept: add an event handler. I don't need to see the details of the
>> implementation. It just works. Well, sort-of-works, but I've already described the
>> problems there. Virtual methods, if you accept derivation as the way of creating new
>> classes, do the same job.
>> ****
>>> So it depends on what kind of design you are referring too. Writing
>>> an C++ implementation is excellent and most of our stuff is written in
>>> this way using interfaces. But I guess I have to wonder why we use
>>> C++ in general. I think it because of its
>>>
>>> - natural scoping capabilities,
>>> - constructors and destructors,
>>> - polymorphisms and interface.
>>>
>>> The virtual interface, a large part, but not the only part.
>>>
>>> Keep in mind you can duplicate all the above within pure C if you
>>> provide the library code to do so.
>> ****
>> And you can write in assembler, too, but it doesn't mean it is a good thing most of the
>> time.
>>
>> I'm working on a course in assembly code, because there are still people who need to work
>> with it (yes, I was surprised, but the uses are legitimate). One of the surprises was the
>> number of people who need to write really tight, high-performance SIMD code (apparently
>> the x64 intrinsics don't produce particularly good code when they are used for this). But
>> it doesn't mean that people should write apps in assembler.
>>
>> If my customer base accepted it, I'd be writing in C# or WPF, but they don't want this. In
>> fact, are opposed to it (I'm not sure I follow the reasoning, but they write the checks,
>> and I want to take their money). So I write in C++, and in a few cases in C (and I just
>> finished a library in C, several thousand lines of code, in which callbacks form a
>> particularly important part of the functionality. But I'd rather have done it in C++ and
>> just supplied a pure virtual method. You would not BELIEVE what I saw done there when I
>> got the library; it was a particularly ugly callback, well, I can't really call it
>> "design", and "kludge" gives it too much dignity, but as redesigned, it is essentially a
>> virtual method mechanism and therefore intellectually manageable, as well as handling a
>> ton of problems the old mechanism simply ignored). So I still use them, but they *should*
>> be avoided as a way of life in most coding. I nearly made all the complexity of the
>> earlier kludge disappear in the new design, which took major rework to get complete and
>> consistent. Doing a callback *right* isn't easy, and most people, I have found, take the
>> easy solution. If you assume that you should avoid them, then you use them only when
>> necessary, and ideally wrap enough syntactic sugar around them to make them go down easily
>> (e.g., virtual methods in C++).
>> joe
>> *****
>> Joseph M. Newcomer [MVP]
>> email: newcomer(a)flounder.com
>> Web: http://www.flounder.com
>> MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5
Prev: "Problems"
Next: How well can TextOut() handle Unicode?