Velocity Reviews > Function Wrapper: Opinions and Critique Desired

# Function Wrapper: Opinions and Critique Desired

I.M. !Knuth
Guest
Posts: n/a

 07-19-2006
A while back, I was mucking around with a recursive function. For
brevity's sake, I'll define it like this:

int func_recurs(int arg1, int arg2, int prev_pos)
{
int crnt_pos = 0;
int result;

/* stuff happens to arg1, arg2, and crnt_pos */

func_recurs(arg1, arg2, (prev_pos + crnt_pos) );

return result;
}

The critical part here (as I'm sure you've figured out already) is that
prev_pos (the previous position) of the last recursion is combined with
crnt_pos (the current positon) of the present recursion and passed along
to become the prev_pos of the next recursion.

But written this way, I had to remember that any call to func_recurs()
always had to look like this:

func_recurs(arg1, arg2, 0);

Frankly, I thought that constant 0 dangling at the end was rather
inelegant. Then it struck me that maybe I could "hide" func_recurs
inside another function so that I wouldn't have to strain my brain
remembering about that pesky third argument; something like:

func_lazymemory(int arg1, int arg2)
{
func_recurs(arg1, arg2, 0);
}

Being new to C, I felt pretty clever for coming up with this all on my
own. But then I thought: "Bah! Smells of kludge. There must be a
better way."

So I changed it to:

int func_recurs(int arg1, int arg2)
{
--> static int prev_pos; /* conveniently init'd to 0 on 1st call */
int crnt_pos = 0;
int result;

/* stuff happens to arg1, arg2, and crnt_pos */

--> prev_pos += crnt_pos; /* adjust for next recursion */
--> func_recurs(arg1, arg2);
--> prev_pos -= crnt_pos; /* restore for current recursion */

return result;
}

Drawing your attention to the four "-->" lines, I then thought: "Boy is
that ugly", but I no longer felt I'd somehow cheated inside my code. I
packed away the function and forgot about it ... until tonight.

Tonight I was browsing through some months' old threads on clc and came
across one that discussed function wrappers. "Cool," I thought. A
response referenced the FAQ, so I pulled it up and had a read. So, my
clever idea is old hat. Figures!

I started thinking again about how I dealt with that function and came
up with some questions and concerns:

1a) Is my use of a wrapper appropriate (or am I ignorant of some wrapper
rule or style convention)?

1b) Wouldn't the wrapper be improved (and the program conserve some
storage) if it were re-written to pass pointer values like this?

func_lazymemory(int *arg1, int *arg2)
{
func_recurs(arg1, arg2, 0);
}

2a) Is one of my solutions better/cleaner/preferable over the other?

2b) Or are they equivalent, and picking one is a matter of (my) personal
style?

3) Is there some other (maybe obvious) solution to ditching that third
argument that I've somehow overlooked?

--
I.M. (definitely) !Knuth

Morris Dovey
Guest
Posts: n/a

 07-19-2006
I.M. !Knuth (in Xns98055B40DA1711011011@81.174.50.80) said:

| 3) Is there some other (maybe obvious) solution to ditching that
| third argument that I've somehow overlooked?

There is usually some other method (no matter what you're doing)

I have two short pieces of recursive code that you might find
interesting:

http://www.iedu.com/mrd/c/getsm.c and
http://www.iedu.com/mrd/c/getsmx.c that deal with a similar situation.

The two are functionally equivalent; but the second module "cheats" in
that it uses a gcc extension to allow embedding one function
declaration inside another. It's non-standard but may have some value
as a thought-provoking device.

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto

Barry Schwarz
Guest
Posts: n/a

 07-20-2006
On Wed, 19 Jul 2006 06:33:14 +0000 (UTC), "I.M. !Knuth"
<(E-Mail Removed)> wrote:

>A while back, I was mucking around with a recursive function. For
>brevity's sake, I'll define it like this:
>
> int func_recurs(int arg1, int arg2, int prev_pos)
> {
> int crnt_pos = 0;
> int result;
>
> /* stuff happens to arg1, arg2, and crnt_pos */
>
> func_recurs(arg1, arg2, (prev_pos + crnt_pos) );
>
> return result;
> }
>
>The critical part here (as I'm sure you've figured out already) is that
>prev_pos (the previous position) of the last recursion is combined with
>crnt_pos (the current positon) of the present recursion and passed along
>to become the prev_pos of the next recursion.
>
>But written this way, I had to remember that any call to func_recurs()
>always had to look like this:
>
> func_recurs(arg1, arg2, 0);
>
>Frankly, I thought that constant 0 dangling at the end was rather
>inelegant. Then it struck me that maybe I could "hide" func_recurs
>inside another function so that I wouldn't have to strain my brain
>remembering about that pesky third argument; something like:
>
> func_lazymemory(int arg1, int arg2)
> {
> func_recurs(arg1, arg2, 0);
> }
>
>Being new to C, I felt pretty clever for coming up with this all on my
>own. But then I thought: "Bah! Smells of kludge. There must be a
>better way."
>
>So I changed it to:
>
> int func_recurs(int arg1, int arg2)
> {
>--> static int prev_pos; /* conveniently init'd to 0 on 1st call */

Just a nit. Static variables are initialized prior to your program
beginning execution and independent of your function.

Remove del for email

Keith Thompson
Guest
Posts: n/a

 07-20-2006
Barry Schwarz <(E-Mail Removed)> writes:
> On Wed, 19 Jul 2006 06:33:14 +0000 (UTC), "I.M. !Knuth"
> <(E-Mail Removed)> wrote:

[...]
>>So I changed it to:
>>
>> int func_recurs(int arg1, int arg2)
>> {
>>--> static int prev_pos; /* conveniently init'd to 0 on 1st call */

>
> Just a nit. Static variables are initialized prior to your program
> beginning execution and independent of your function.

True -- but, by the as-if rule, an implementation conceivably *could*
delay the initialization until the first call. (Nothing outside the
function can see the variable before that and detect that it hasn't
been initialized. Local static variables can be seen via pointers
outside the function that defines them, but there's no way to
initialize such a pointer before calling the function.)

But I can't think of a good reason for an implementation to do such a
silly thing.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

I.M. !Knuth
Guest
Posts: n/a

 07-20-2006
Morris Dovey <(E-Mail Removed)> wrote:

<snip>
> I have two short pieces of recursive code that you might find
> interesting:
>
> http://www.iedu.com/mrd/c/getsm.c and
> http://www.iedu.com/mrd/c/getsmx.c that deal with a similar situation.
>
> The two are functionally equivalent; but the second module "cheats" in
> that it uses a gcc extension to allow embedding one function
> declaration inside another. It's non-standard but may have some value
> as a thought-provoking device.

My, what large comment blocks you have.

I found a number of (even trivial) things thought-provoking. The
imbedded function (getsmx.c) is outright trippy; it would have taken me
a while just to find it without your comments marking its start and end,
and even more time to figure out was going on.

Where you comment like this:

#include <stdio.h> /* fgetc() */

I've been commenting in the reverse:

fgetc(foo); /* <stdio.h> */

I haven't yet noodled much with structures, nor braved malloc at all, so
I'm a bit lost on how you entirely eliminated...

typedef struct {...} getstr; /* getsm.c */

....from getsmx.c. Though I can see where the structure's contents moved
to. I'll take another look after I get some sleep...

Why have some local variables been explicitly declared with automatic
storage duration?

Having an #ifdef encapsulated "in-line" test main() is frickin' cool. I'll
have to borrow this idea.

I note you use **argv as a parameter to main() instead of the conventional
*argv[]. I like that. The latter confused and frightened me when I was
first learning pointers. Even now, the former seems clearer to me.

I note also that you don't make use at all of argc. This made me laugh. I
recently finished a program that made extensive use of **argv, but I
couldn't find a use for argc. Everytime I re-compiled it I got the
message:

Warning: 'argc' initialized but never used.

....or some such. I contemplated putting in some dummy code just to make
the warning go away. Does gcc not spit out a similar warning?

Thank you most kindly for letting me peek inside your code.

--
I.M. (definitely) !Knuth

I.M. !Knuth
Guest
Posts: n/a

 07-20-2006
Barry Schwarz <(E-Mail Removed)> wrote:

> On Wed, 19 Jul 2006 06:33:14 +0000 (UTC), "I.M. !Knuth"
> <(E-Mail Removed)> wrote:

<snip>
>>--> static int prev_pos; /* conveniently init'd to 0 on 1st call */

>
> Just a nit. Static variables are initialized prior to your program
> beginning execution and independent of your function.

D'oh! I knew that. Really, I did.

--
I.M. (definitely) !Knuth

I.M. !Knuth
Guest
Posts: n/a

 07-20-2006
Keith Thompson <(E-Mail Removed)> wrote:

> Barry Schwarz <(E-Mail Removed)> writes:
>> On Wed, 19 Jul 2006 06:33:14 +0000 (UTC), "I.M. !Knuth"
>> <(E-Mail Removed)> wrote:

<snip>
>>>--> static int prev_pos; /* conveniently init'd to 0 on 1st call */

>>
>> Just a nit. Static variables are initialized prior to your program
>> beginning execution and independent of your function.

>
> True -- but, by the as-if rule, an implementation conceivably *could*
> delay the initialization until the first call. (Nothing outside the
> function can see the variable before that and detect that it hasn't
> been initialized. Local static variables can be seen via pointers
> outside the function that defines them, but there's no way to
> initialize such a pointer before calling the function.)
>
> But I can't think of a good reason for an implementation to do such a
> silly thing.

So, hypothetically, I only look dumb under some implementation-specific
circumstances.

BTW, what's the "as-if rule"?

--
I.M. (definitely) !Knuth

Keith Thompson
Guest
Posts: n/a

 07-20-2006
"I.M. !Knuth" <(E-Mail Removed)> writes:
> Keith Thompson <(E-Mail Removed)> wrote:
>> Barry Schwarz <(E-Mail Removed)> writes:
>>> On Wed, 19 Jul 2006 06:33:14 +0000 (UTC), "I.M. !Knuth"
>>> <(E-Mail Removed)> wrote:

> <snip>
>>>>--> static int prev_pos; /* conveniently init'd to 0 on 1st call */
>>>
>>> Just a nit. Static variables are initialized prior to your program
>>> beginning execution and independent of your function.

>>
>> True -- but, by the as-if rule, an implementation conceivably *could*
>> delay the initialization until the first call. (Nothing outside the
>> function can see the variable before that and detect that it hasn't
>> been initialized. Local static variables can be seen via pointers
>> outside the function that defines them, but there's no way to
>> initialize such a pointer before calling the function.)
>>
>> But I can't think of a good reason for an implementation to do such a
>> silly thing.

>
> So, hypothetically, I only look dumb under some implementation-specific
> circumstances.

Um, sure. }

> BTW, what's the "as-if rule"?

The general idea is that the standard describes the behavior of an
abstract machine, but the actual generated code is allowed to behave
differently as long as the result is *as if* it followed the semantics
described in the standard. It allows for optimizations such as
eliminating calculations whose results are never used.

C99 5.1.2.2.3p3:

In the abstract machine, all expressions are evaluated as
specified by the semantics. An actual implementation need not
evaluate part of an expression if it can deduce that its value is
not used and that no needed side effects are produced (including
any caused by calling a function or accessing a volatile object).

C99 5.1.2.2.3p5:

The least requirements on a conforming implementation are:

-- At sequence points, volatile objects are stable in the sense
that previous accesses are complete and subsequent accesses
have not yet occurred.

-- At program termination, all data written into files shall be
identical to the result that execution of the program according
to the abstract semantics would have produced.

-- The input and output dynamics of interactive devices shall take
place as specified in 7.19.3. The intent of these requirements
is that unbuffered or line-buffered output appear as soon as
possible, to ensure that prompting messages actually appear
prior to a program waiting for input.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

jaysome
Guest
Posts: n/a

 07-20-2006
On Thu, 20 Jul 2006 06:29:49 +0000 (UTC), "I.M. !Knuth"
<(E-Mail Removed)> wrote:

>Keith Thompson <(E-Mail Removed)> wrote:
>
>> Barry Schwarz <(E-Mail Removed)> writes:
>>> On Wed, 19 Jul 2006 06:33:14 +0000 (UTC), "I.M. !Knuth"
>>> <(E-Mail Removed)> wrote:

><snip>
>>>>--> static int prev_pos; /* conveniently init'd to 0 on 1st call */
>>>
>>> Just a nit. Static variables are initialized prior to your program
>>> beginning execution and independent of your function.

>>
>> True -- but, by the as-if rule, an implementation conceivably *could*
>> delay the initialization until the first call. (Nothing outside the
>> function can see the variable before that and detect that it hasn't
>> been initialized. Local static variables can be seen via pointers
>> outside the function that defines them, but there's no way to
>> initialize such a pointer before calling the function.)
>>
>> But I can't think of a good reason for an implementation to do such a
>> silly thing.

>
>So, hypothetically, I only look dumb under some implementation-specific
>circumstances.
>
>BTW, what's the "as-if rule"?

The intention was to provide direction through example. The examples
were meant to be unambiguous. I think the committee achieved that for
the most part.

Best regards
--
jay

Keith Thompson
Guest
Posts: n/a

 07-20-2006
jaysome <(E-Mail Removed)> writes:
> On Thu, 20 Jul 2006 06:29:49 +0000 (UTC), "I.M. !Knuth"
> <(E-Mail Removed)> wrote:

[...]
>>BTW, what's the "as-if rule"?

>
> The intention was to provide direction through example. The examples
> were meant to be unambiguous. I think the committee achieved that for
> the most part.

Um, what does that have to with the "as-if" rule?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.