From -6229351653833338468
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,9d57bb38940f08c2
X-Google-Attributes: gidf78e5,public
From: AllanW@my-dejanews.com
Subject: Re: References to functions allowed?
Date: 1999/01/19
Message-ID: <780u86$vj4$1@nnrp1.dejanews.com>
X-Deja-AN: 434448184
X-NNTP-Posting-Host: 199.125.171.8
Approved: stephen.clamage@sun.com (comp.std.c++)
References: <36A222B3.E51DFD28@ibm.net>
X-Snookums: I love you
X-UID: 0000000001
X-Status: $$$T
X-Http-User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)
X-Http-Proxy: 1.1 x6.dejanews.com:80 (Squid/1.1.22) for client 199.125.171.8
Organization: Deja News - The Leader in Internet Discussion
X-Article-Creation-Date: Tue Jan 19 03:30:13 1999 GMT
Newsgroups: comp.std.c++
Originator: clamage@taumet


In article <36A222B3.E51DFD28@ibm.net>,
  bijuthom@ibm.net wrote:
> Hello,
Hi!

> Does the C++ standard allow references to functions? For example, is the
> following legal?
>
> int f () {}
>
> int (&rf)() = f;

It ought to; it really ought to.

Consider that C++ can do almost anything that assembly language can do.
But there is one powerful programming technique that has fallen out of
favor recently, a mood swing which has so blinded the C++ standardization
committee that it wasn't even considered for inclusion in the language.
Which is bad, because the technique I am referring to is time-honored,
well-understood, and very very powerful. Of course I cannot be talking
about anything other than self-modifying code.

    #include <iostream>
    const int MAXVAL = 5;
    int nextval(int) { return 0; }
    int decrement(int);
    int increment(int x) {
        ++x;                // Must update BEFORE overwrite
        if (x>=MAXVAL) {
            int (&me)(int) = nextval;
            int (&const other)(int) = decrement;
            me = other; // Overwrite nextval() with copy of decrement
        }
        return x;
    }
    int decrement(int x) {
        --x;                // Must update BEFORE overwrite
        if (x<=0) {
            int (&me)(int) = nextval;
            int (&const other)(int) = increment;
            me = other; // Overwrite nextval() with copy of increment
        }
        return x;
    }
    int main() {
        // Also inits nextval() with copy of increment:
        int v = decrement(1);
        std::cout << v;
        for (int i=1; i<=20; ++i) std::cout << ',' << (v=nextval(v));
        std::cout << std::endl;
    }
    // Output: 0,1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,4,3,2,1,0

As you can see, the first thing main() does is to call decrement(). That
function causes the code in function increment() to overwrite function
nextval(). From then on we call nextval() only. When we have incremented
as much as we want to, nextval() overwrites itself with a copy of
decrement(), which takes effect next time the function is called.

I hear some of you object right now. "Couldn't you accomplish the same
thing by having two classes with virtual functions, and then overwriting
the vtables with the new function addresses?" Perhaps, but this gets
tricky. A simpler technique would be to modify the vptr itself, to point
to the other vtable. But even this crystal-clear idea has drawbacks; it
just isn't a general-purpose solution to the problem. To see why, imagine
that main() is a legacy function that you cannot make changes to. Since
main() calls nextval() directly, the only general-purpose solution to
the problem is to overwrite the code in nextval() at run time.

An even worse idea is to create a fancy version of nextval() with large
if-then sections, or to use some method that checks flags (or anything
else) and "dispatches" to some other function to do the actual work. As
all assembly-language programmers know, irresponsible solutions like
this cause extra memory fetches. For instance, a Cray computer might
take as much as 20 nanoseconds longer if the above program were written
in this way. If run 1000 times a day for 30 years, this would add up to
well over 0.2 seconds -- that's 0.2 very expensive seconds of Cray CPU
time, and also 0.2 seconds of your personal time that you could have
spent with your loved ones, or simply relaxing.

"But," say some language lawyers, "there are some compilers that attempt
to put all executable code into a 'ROM-able' segment. ROM can't be
overwritten!" This is true, and it represents the biggest menace to our
profession. Clearly there is ONLY ONE reason for compilers to generate
code like this: To threaten our God-given right to create code that
modifies itself. Compiler writers will continue to act in antisocial
ways such as this until we hit them in the pocketbook. BOYCOTT! We must
all boycott any compiler that tries to move your code somewhere where you
can't modify it!

Note that self-modifying code is not the only useful purpose of
references to functions. There's also the issue of function sizes. For
instance, suppose that your program has profiled two provably-correct
functions, FunctionA() and FunctionB(), either one of which can be used
in your program. If you have found them to have almost identical run-time
charactaristics, then you will want to use whichever function has a
smaller memory footprint. But you can't compare sizeof(FunctionA) to
sizeof(FunctionB) -- that compares the size of the function POINTERs,
which will always be equal. If you had a reference to the actual
function itself, sizeof() would give you a true number.

By the way, the code above has a minor problem. Note that the stub
version of nextval() probably generates less code than either
increment() or decrement(). When we try to overwrite the function,
we'll... uh... get a memory overwrite. Detecting this can be as simple
as inserting
    assert(sizeof(me)>=sizeof(other));
into the appropriate place in both increment() and decrement(). Give
yourself 10 points if you caught this on your own.


8^>   :-)   8^>   :-)   8^>   :-)   8^>   :-)   8^>   :-)   8^>


----
AllanW@my-dejanews.com is a "Spam Magnet".
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]




