Translation-Time Type Information


S

Shao Miller

Hello Readers,

I'd like to offer some code which some of you might find interesting.

In the code, the func() macro effectively expands to a function which
depends on the type of the argument to the macro. This is useful for
when you wish to treat identifiers differently based on the identified
type. The function can be any function type, returning any type.

Requirements are:
- A "wrapper" type for any type you are interested in using with this
macro
- The wrapper type has a sizeof() being greater than or equal to
sizeof(char*)
- The undefined behaviour due to the "magic" where pointer arithmetic
jumps from one array object to another, dis-joint array object, even
though there are objects of the same type within the latter array
object

I am interested in:
- If anyone can identify an implementation which produces results
different than those found in the demonstration below, or at
http://codepad.org/Cf5zh5xS
- If anyone has any feedback about a "better way" to produce a macro
with similar functionality

The following demonstration can be compiled with 'gcc -ansi -pedantic -
Werror'.
-----
/*
* (C) Shao Miller, 2010
*
* Translation-time type information.
* At the cost of each wrapper type being >= sizeof(char*)
*/
#include <stddef.h>
#include <stdio.h>

enum types {
types_none,
types_char,
types_short,
types_int,
types_long,
types_total
};

union char_wrapper;
typedef char (*char_func_type)(union char_wrapper *this);

union short_wrapper;
typedef short (*short_func_type)(union short_wrapper *this);

/* etc. */

union char_wrapper {
char value;
char (*type)[types_char];
char_func_type func[1];
};

union short_wrapper {
short value;
char (*type)[types_short];
short_func_type func[1];
};

/* etc. */

/* This matches char_func_type */
char char_func(union char_wrapper *this) {
puts("char_func()");
return this->value;
}

/* This matches short_func_type */
short short_func(union short_wrapper *this) {
puts("short_func()");
return this->value;
}

/* etc. */

union any_func {
char_func_type char_func;
short_func_type short_func;
/* etc. */
};

union any_func funcs[types_total];

void init_funcs(void) {
funcs[types_char].char_func = char_func;
funcs[types_short].short_func = short_func;
/* etc. */
}

#define func(x) \
\
(*(x.func - ((char**)x.func - (char**)funcs) + sizeof(*x.type)))(&x)

int main(void) {
union char_wrapper foo;
char foo_test;
union short_wrapper bar;
short bar_test;

init_funcs();

if (sizeof(*foo.type) == types_char) {
puts("foo was indeed a char_wrapper");
}
if (sizeof(*bar.type) == types_short) {
puts("bar was indeed a short_wrapper");
}

foo_test = func(foo);
bar_test = func(bar);

return 0;
}
-----

Sample output:

foo was indeed a char_wrapper
bar was indeed a short_wrapper
char_func()
short_func()

Thank you for your attention,

- Shao Miller
 
Ad

Advertisements

E

Eric Sosman

Hello Readers,

I'd like to offer some code which some of you might find interesting.

In the code, the func() macro effectively expands to a function which
depends on the type of the argument to the macro. This is useful for
when you wish to treat identifiers differently based on the identified
type. The function can be any function type, returning any type.

Requirements are:
- A "wrapper" type for any type you are interested in using with this
macro
- The wrapper type has a sizeof() being greater than or equal to
sizeof(char*)
- The undefined behaviour due to the "magic" where pointer arithmetic
jumps from one array object to another, dis-joint array object, even
though there are objects of the same type within the latter array
object

I am interested in:
- If anyone can identify an implementation which produces results
different than those found in the demonstration below, or at
http://codepad.org/Cf5zh5xS
- If anyone has any feedback about a "better way" to produce a macro
with similar functionality

It seems to me that the expansion of your func() macro invokes
undefined behavior, in that it subtracts two pointers that don't point
into (or just past) the same array. You're probably getting away with
it because the optimizer sees a variant of `p - (p - q)' and turns it
into just `q', avoiding the undefined `p-q' step. But that means the
undefined bit was unnecessary to begin with, and you could just have
written `q', or more fully

#define func(x) funcs[sizeof x.type / sizeof(char*)](&x)

.... which you could simplify further (by making the `type' member an
array of char instead of an array of char*, which might also save
some memory) to

#define func(x) funcs[sizeof x.type](&x)

This allows you to get rid of the `func' members in your wrapper
unions, as they no longer serve any purpose (they never did, except
to invoke gratuitous undefined behavior).

The trick of pairing each value with an unused array whose sizeof
is a type code is one I hadn't seen before, and gets points for
originality. But real programs often have hundreds of types, not just
the four of your example, and the technique is likely to prove unwieldy.
Even in your tiny four-type example you found it convenient to use
the comment /* etc. */ four times to omit essentially half the code.
C provides seventeen "built-in" arithmetic types, without even touching
on things like size_t and time_t, nor <stdint.h>. Nor have we counted
user-defined types like structs, unions, arrays, and pointers to all
these other things ...

Meanwhile, all our expressions balloon because we must append
`.value' to every variable name. `x = (-b + sqrt(b*b - 4*a*c)/(2*a);'
becomes

x.value = (-b.value
+ sqrt(b.value*b.value - 4*a.value*c.value)
/ (2*a.value);

It's an interesting hack, but not to my taste even after cleanup.
 
S

Shao Miller

It seems to me that the expansion of your func() macro invokes
undefined behavior, in that it subtracts two pointers that don't point
into (or just past) the same array.

As mentioned in the original post, yes. The U. B. is a requirement.
You have re-stated, here. That's fine.

You're probably getting away with
it because the optimizer sees a variant of `p - (p - q)' and turns it
into just `q', avoiding the undefined `p-q' step. But that means the
undefined bit was unnecessary to begin with, and you could just have
written `q', or more fully

#define func(x) funcs[sizeof x.type / sizeof(char*)](&x)

No. Note the type of 'funcs'. You have missed some of the "magic".
In the 'union char_wrapper', for example, the 'func' member has an
arbitrary function type. If we wish for the 'func()' macro to expand
to an arbitrary function type based on the type of the macro's
argument, your #define above will not work. With your #define above,
there could be only one possible function type as a result of the
preprocessor expansion.

There is no dependence on any compiler optimization. The U. B.
subtraction of the two pointers yields a signed integer. That integer
is then subtracted from the 'func' member to yield (and here's the
magic): A pointer to a pointer to a function with some specific type.
Thus the 'func()' macro expands to a function call with possibly
different function types (think return types) based on different
"wrapper" types.
... which you could simplify further (by making the `type' member an
array of char instead of an array of char*, which might also save
some memory)

Please re-read the code. 'type' is not an array of char*. It is a
pointer to an array of char. Thus, there is no memory requirement to
relax beyond what's stated in the comments regarding "cost" at the
beginning of the code.
#define func(x) funcs[sizeof x.type](&x)

Not applicable due to previous corrections.
This allows you to get rid of the `func' members in your wrapper
unions, as they no longer serve any purpose (they never did, except
to invoke gratuitous undefined behavior).

They serve the "magic" purpose mentioned above.
The trick of pairing each value with an unused array whose sizeof
is a type code is one I hadn't seen before, and gets points for
originality.

Thank you for the points. I would have said each "wrapper" _type_ is
paired with with an unusued _pointer_, however. The sizeof() magic
yields an integer constant expression based on an array which is never
allocated anywhere, ever.
But real programs often have hundreds of types, not just
the four of your example, and the technique is likely to prove unwieldy.
Even in your tiny four-type example you found it convenient to use
the comment /* etc. */ four times to omit essentially half the code.
C provides seventeen "built-in" arithmetic types, without even touching
on things like size_t and time_t, nor <stdint.h>. Nor have we counted
user-defined types like structs, unions, arrays, and pointers to all
these other things ...

So-called "x-macros" could help with this. You can see a pattern in
the code, so I believe that some macros could help to alleviate a
significant portion of the writing. I will try to post such an
example in the future.

The only use case provided in the original post was in regards to
having a 'func()' macro which expands differently for different
types. If you want to use x-macros to produce "wrapper" types for
every type you can think of, so be it. If you have only a handful of
types, but wish to provide the programmer with a means to use _one_
macro to do something completely different for each of those types, so
be it. If you only have one type, it still could be interesting that
there is some "translation-time type information" available about that
type, _without_ having any type information _allocated_ post-
translation.
Meanwhile, all our expressions balloon because we must append
`.value' to every variable name. `x = (-b + sqrt(b*b - 4*a*c)/(2*a);'
becomes

x.value = (-b.value
+ sqrt(b.value*b.value - 4*a.value*c.value)
/ (2*a.value);

I don't understand why this is important. Please consider that
'func()' is a single macro, but that you could just as easily have a
'get()' and a 'set()' macro, which expand differently for different
types...
It's an interesting hack, but not to my taste even after cleanup.

Thank you for your feedback, Eric. I do appreciate it. I also do
believe it's a bit hasty to suggest "cleanup" when you haven't fully
understood the code, however. Have a nice day.
 
E

Eric Sosman

As mentioned in the original post, yes. The U. B. is a requirement.
You have re-stated, here. That's fine.

It's an odd sort of design that *requires* its implementation
to indulge in undefined behavior ...
No. Note the type of 'funcs'. You have missed some of the "magic".
[...]

Too deep for me, I guess. I think I'll choose not to swim there.
 
K

Kenny McCormack

As mentioned in the original post, yes. The U. B. is a requirement.
You have re-stated, here. That's fine.

It's an odd sort of design that *requires* its implementation
to indulge in undefined behavior ...
No. Note the type of 'funcs'. You have missed some of the "magic".
[...]

Too deep for me, I guess. I think I'll choose not to swim there.

I heard about this one time, back in '93 (or maybe '94) when somebody on
CLC actually liked and approved of some substantive contribution posted
to the newsgroup (by someone other than the person rendering the
opinion).

Was quite the sensation. Made all the papers.

Clarification (In case anyone is too thick to get it): In CLC, the
dominant mode-of-thinking (groupthink) requires that all substantive
contributions are "dissed". If anyone posts anything positive (i.e.,
approves of something someone else did), they will lose their clique
membership.

You see this all the time with Jacob's posts.

--
No, I haven't, that's why I'm asking questions. If you won't help me,
why don't you just go find your lost manhood elsewhere.

CLC in a nutshell.
 
E

Eric Sosman

[...]
Meanwhile, all our expressions balloon because we must append
`.value' to every variable name. `x = (-b + sqrt(b*b - 4*a*c)/(2*a);'
becomes

x.value = (-b.value
+ sqrt(b.value*b.value - 4*a.value*c.value)
/ (2*a.value);

I don't understand why this is important. Please consider that
'func()' is a single macro, but that you could just as easily have a
'get()' and a 'set()' macro, which expand differently for different
types...

All right, then:

set(x, (-get(b) + sqrt(get(b)*get(b) - 4*get(a)*get(c))
/ (2*get(a));

.... still seems a touch verbose. Or consider

for (set(i, get(m)); get(i) < get(n); set(i, get(i)+1))
Thank you for your feedback, Eric. I do appreciate it. I also do
believe it's a bit hasty to suggest "cleanup" when you haven't fully
understood the code, however.

My mistake. *Definitely* something I should avoid, then.
 
Ad

Advertisements

S

Shao Miller

Specifically, there are three points of undefined behaviour in the
example code that I am immediately aware of:

1. In the 'char** - char**' subtraction, the specification of
n1256.pdf (I know that's not ANSI C), section 6.5.6, Semantics point
#9, is not entirely clear about what happens if both pointers _do_not_
point within the same array object. We may assume the behaviour is
undefined, perhaps.

2. In the addition of the resulting ptrdiff_t from point #1 (above) to
the 'func' member, the specification of n1256.pdf, section 6.5.6,
Semantics point #8, details that the result of this addition would be
undefined since it would not point to an element of the same array
object, or one past its last element.

3. In the demonstration code, the 'char_func()' and 'short_func()'
functions return the 'value' member of the pointed-to-union, but the
demonstration neglects to assign a value to this object in 'main()'.
It is somewhat trivial for the demonstration and very easily remedied.

There is another point in the example code that might warrant
attention:

1. In the addition of the resulting ptrdiff_t from point #1 (above) to
the 'func' member, the code assumes that the 'sizeof' the function
pointer is equal to the alignment requirement for that function
pointer.

I believe that all of the above points can be addressed to produce
somewhat similar code without any undefined behaviour or concerns.

In U. B. points #1 and #2, we are concerned with pointers of the same
type pointing beyond the bounds of the same array object. That is,
there could be "holes in the Universe" as we try to jump between array
objects. Pointers of a particular type are only guaranteed to
represent an address meeting the _alignment_ constraint for the
referenced type, but that doesn't mean that one can add/subtract a
signed integer to one pointer and yield any desired pointer of the
same type; the resulting pointer is constrained to always be a
distance (in bytes) away from the original that is divisible by the
'sizeof' the referenced type.

One potential solution is to actually "build the Universe" before
performing these operations. For example, you could have a union
whose members are of any type you might work with, then allocate an
array of such unions and only work with its elements. This could
waste space, but would guarantee that your pointers never go out-of-
bounds for the array object. This would also satisfy the additional
concern #1.

U. B. #3 is trivial to address, as mentioned.

So a possibly perceived limitation of C is that while the "substrate
of the Universe" can be considered arrays of 'unsigned char', that
"Universe" need not be contiguous. But since work-arounds exist
(above):

- Could it be useful to allow for the specification of contiguity in
code via a new C keyword?

- Could it be useful to have a language feature which has a similar
use to the 'func()' macro in the demonstration code? (Type-dependent
expansion.)

- Could it be useful to allow for unions and structs to have members
which _cannot_ be assigned to and do not impact the size? Consider
how the 'type' member never requires a value, but is nonetheless
useful. Unfortunately, it _does_ impact the 'sizeof' the union (or
struct). Such members could be considered meta-data about the type.
"Ghost" members, if you will.

- Could it be useful to revisit casts and allow for an object's
identifier to be used to cast? Thus the 'func' member of the
"wrapper" types in the demonstration code could have been used to
directly cast an element of the 'funcs' array. (Which may contain an
object of that type.) We already allow for an object's identifier to
be used with 'sizeof', besides types.

None of the above is a suggestion for run-time type information, but
for translation-time type information.

Thanks for reading.

- Shao Miller
 
N

Nick Keighley

Clarification (In case anyone is too thick to get it): In CLC, the
dominant mode-of-thinking (groupthink) requires that all substantive
contributions are "dissed".  If anyone posts anything positive (i.e.,
approves of something someone else did), they will lose their clique
membership.

You see this all the time with Jacob's posts.

but you, of course, are too cunning for us and avoid this trap by
making no substantive contributions
 
K

Kenny McCormack

but you, of course, are too cunning for us and avoid this trap by
making no substantive contributions

Nor do you - or anyone else - other than Jacob and the occasional newbie
(such as Mr. Miller here). We all learn quickly not to bother.

Note: "substantive" here means more than you think it does.

--
No, I haven't, that's why I'm asking questions. If you won't help me,
why don't you just go find your lost manhood elsewhere.

CLC in a nutshell.
 
S

Shao Miller

Good day Readers,

I have refined the code to avoid undefined and implementation-specific
behaviour altogether, I believe. Essentially the purpose is to yield
a single macro 'get()' which expands to an appropriate function call,
dependent on the type specified by an association produced by the
'add_get()' macro. The wrapper types from the original post are gone.

Please point out any undefined, unspecified, or implementation-defined
points if any are identifiable.

Demonstration code available at http://codepad.org/5m8bw56n and also
follows:
-----
/**
* (C) Shao Miller, 2010
*
* Translation-time type information.
**/

/* For any operation */
#define phony_op_ptr(op_type) ((op_type*)0)
#define op_index_is(index) char (*op_index)[index]
#define op_index(op_type) (sizeof(*(phony_op_ptr(op_type)->op_index)))

/* For the get() operation */
#define add_get(type, x) typedef type ## _get_u _op_get_ ## x
#define get(x) \
(((_op_get_ ## x*)((funcs) + (op_index(_op_get_ ## x))))->func(&x))

/* Program */
#include <stddef.h>
#include <stdio.h>

typedef char (*char_get_func_type)(char *this);
typedef short (*short_get_func_type)(short *this);

enum {
ops_none,
ops_char_get,
ops_short_get,
ops_total
};

typedef union {
char_get_func_type func;
op_index_is(ops_char_get);
} char_get_u;
typedef union {
short_get_func_type func;
op_index_is(ops_short_get);
} short_get_u;

/* This matches char_func_type */
char char_get_func(char *this) {
puts("char_func()");
return *this;
}
/* This matches short_func_type */
short short_get_func(short *this) {
puts("short_func()");
return *this;
}

typedef union {
char *any;
char_get_u char_get;
short_get_u short_get;
/* etc. */
} any_op_u;

static const any_op_u funcs[] = {
0,
(char*)char_get_func,
(char*)short_get_func,
};

int main(void) {
char c;
add_get(char, c);
char d;
short s;
add_get(short, s);
short t;

c = 'c';
s = 12;

d = get(c);
t = get(s);

return 0;
}

-----
Demonstration output:

char_func()
short_func()
-----
How 'main()' preprocesses:

int main(void) {
char c;
typedef char_get_u _op_get_c;
char d;
short s;
typedef short_get_u _op_get_s;
short t;

c = 'c';
s = 12;

d = (((_op_get_c*)((funcs) + ((sizeof(*(((_op_get_c*)0)-
op_index))))))->func(&c));
t = (((_op_get_s*)((funcs) + ((sizeof(*(((_op_get_s*)0)-
op_index))))))->func(&s));

return 0;
}

Thank you for reading! I hope somebody finds it useful for using
single macros across multiple types.

- Shao Miller
 
T

Tim Rentsch

Shao Miller said:
Good day Readers,

I have refined the code to avoid undefined and implementation-specific
behaviour altogether, I believe. [snip elaboration]

This may be a clever idea, but what is it good for?
Even ignoring the costs of setting up the machinery,
it's hard to see any significant benefits from
applying it. Do you have any kind of real world
example, where there is some reasonable amount of
benefit, that might provide some degree of motivation for
using something like this?
 
Ad

Advertisements

S

Shao Miller

Thank you for your feedback questions, Tim.

Please consider the constraint in C that one cannot #define from
within a preprocessor macro. Thus if you are trying to provide the
programmer with a particular "operation" with implementations of that
operation across different types, the programmer typically needs to
use something like 'get_char(x)', 'get_short(x)', etc., or even
'get(char, x)', 'get(short,x)', etc.

Using a single macro 'get()' allows for the surrounding code to be
used in "x-macro" situations, where you wish to have automated
generation of code via #inclusion. It also means that a change in
decision from 'char foo;' to 'struct bar foo;' does not require a
replace-all throughout the code, but merely where the type and
'add_get()' (for example) are specified.

The purpose for such a "get()" itself would be something like a
generalization of pointer dereferencing. Split into 'get()' and
'set()', you can use such macros throughout the codebase (provide a
familiar facility to programmers) with minimal setup ('add_get() for
each identifier' and a "setting up the machinery" header).

"Operations" such as 'get()' and 'set()' could further be grouped
together and you could use a minimal macro such as 'declare(char, c);'
versus 'char c;' but establish all of the associated operations in the
group.

The demonstration code also hints at a way to perform counting across
headers (via 'sizeof' and types which are never allocated), which
might be useful. I don't know of another way to do that in C (while
making no claim that there is no such way.)

Real-world-wise, I can _now_ start looking around to see where it
could benefit. I'm sorry that I cannot provide more examples at this
time. Can you think of any? The reason I worked at this was so that
I can write valid ANSI C that has a personal aesthetic to it, that
works around some of the C language limitations that I have
_perceived_ (again, I'm not C expert), that wouldn't be completely
incomprehensible to other programmers, and that might even be useful
to them.

What do you believe the "costs of setting up the machinery" to be
like? What do you think the impact of the 'funcs' array's size might
be like, or the code's use of function pointers from that array
instead of direct calls?
 
T

Tim Rentsch

Shao Miller said:
Thank you for your feedback questions, Tim.

My pleasure.
Real-world-wise, I can _now_ start looking around to see where it
could benefit. I'm sorry that I cannot provide more examples at this
time. Can you think of any?

I can't, that's why I asked the question.
The reason I worked at this was so that
I can write valid ANSI C that has a personal aesthetic to it, that
works around some of the C language limitations that I have
_perceived_ (again, I'm not C expert), that wouldn't be completely
incomprehensible to other programmers, and that might even be useful
to them.

What you're doing may very well be useful. I'm just not
sure for what.
What do you believe the "costs of setting up the machinery" to be
like? What do you think the impact of the 'funcs' array's size might
be like, or the code's use of function pointers from that array
instead of direct calls?

My first concern is probably scaling. How does what you're
doing scale up to greater numbers and varieties of types
and greater numbers of functions? Can the necessary
scaffolding be abstracted (via macro definitions or
some such) so that it is less obtrusive? Where are
the edges where it breaks down? How do combinations
of type-specific functions work? Is the interaction
linear, exponential, or does it sometimes not work
at all? Generally speaking, how well does it work
in larger programs rather than just small examples?

My second concern is effect on tool usage and the
development process. What does using this kind
mechanism do to compiler error messages? What effect
does if have on debugging using a standard debugger
such as gdb? What are the implications for search
or cross-referencing tools such as grep, tags,
or similar functionalities? The mechanisms appear
to satisfy the requirements of compiling a well-formed
program, but what about all the other activities
involving source code that are part of a normal
development process? I expect that there will
be some effects in these areas, but I'm not sure
what they will be, let alone quantifying the cost
of dealing with those effects.
 
S

Shao Miller

I can't, that's why I asked the question.

Very well.
What you're doing may very well be useful.  I'm just not
sure for what.

Thank you for allowing for this possibility of usefulness in your
response.
My first concern is probably scaling.  How does what you're
doing scale up to greater numbers and varieties of types
and greater numbers of functions?

I will attempt to respond to this and further questions in regards to
the recent code example.

Each "operation" requires that a union of a function pointer and an
unused pointer to a never-allocated array of 'char' be allocated, so
the table must be at least the 'sizeof' of the largest such union,
times the number of implemented "operations." This is redundant due
to the ability of the code to call functions directly, but seemingly
necessary.

The implementation limits may be a factor for consideration of:
- Number of types produced (union, function pointer, typedef)
- Number of parentheses in expressions, sub-expressions
 Can the necessary
scaffolding be abstracted (via macro definitions or
some such) so that it is less obtrusive?

I believe that is quite possible.
 Where are
the edges where it breaks down?

My guess would be that in an expression with many levels of sub-
expressions, the implementation's limits for sub-expressions could be
a cause for concern.

The 'get()' macro given would break down from use of '&', '*', '++',
'[x]' etc., since it expects a pure identifier.
 How do combinations
of type-specific functions work? Is the interaction
linear, exponential, or does it sometimes not work
at all?

I'm not sure about these questions' meanings, I'm afraid.
 Generally speaking, how well does it work
in larger programs rather than just small examples?

Some examples of limitations that might be encountered in larger
programs are given above.
My second concern is effect on tool usage and the
development process.  What does using this kind
mechanism do to compiler error messages?

By using 'get(x)' instead of 'get(foo, x)' or 'get_foo(x)', one is not
looking at the type of 'x'. That is exactly the purpose, but can be
exactly a point of programmer error. If someone uses an identifier
for which the "operation" is not implemented, the compiler should
describe its inability to cast to a type carrying the name of the
identifier. This type's name could involve a clue for a programmer
when seen in an error message.
 What effect
does if have on debugging using a standard debugger
such as gdb?

Like any macro, a single line of source making use of a macro
obfuscates what operations that macro performs. The debugger user
would see a sudden jump into the type-specific implementation for the
"operation" as the function pointer in the table of "operations" is
called.
 What are the implications for search
or cross-referencing tools such as grep, tags,
or similar functionalities?

If one wished to 'grep' for all instances where 'char_get_func()' is
effectively called via the 'get()' macro, one would need to search for
all 'add_get()' lines including 'char'. We might expect there to be
less of these than there would be with an alternative 'get_char()'.
One would need to observe the identifiers involved in the 'add_get()'
operations and then search for all 'get()' instances involving those
identifiers.
 The mechanisms appear
to satisfy the requirements of compiling a well-formed
program, but what about all the other activities
involving source code that are part of a normal
development process?  I expect that there will
be some effects in these areas, but I'm not sure
what they will be, let alone quantifying the cost
of dealing with those effects.

Absolutely.

Over-all, these are great questions. I think the only way to begin to
explore the answer space for these would be with a sampling of
concrete, non-trivial examples. Until such a time as that arrives, we
can certainly theorize and discuss, but without such a useful frame of
reference.

I will try to come up with an example which implements something akin
to 'memcpy()'. Instead of walking a contiguous, allocated vector of
bytes (the "object", in C), the getting, setting, incrementing will
take place via some of the "magic" discussed previously.

I also believe that it's good to have a record, in case anyone at all
finds that it could fill their need.

We could discuss what alternatives could exist if only there were
certain ANSI (C89) C language features, but it's too late for ANSI C
to contain them. This code is meant to comply with ANSI C (regardless
of earlier 'n1256.pdf' references).
 
T

Tim Rentsch

Shao Miller said:
I can't, that's why I asked the question.

Very well.
What you're doing may very well be useful. I'm just not
sure for what.

Thank you for allowing for this possibility of usefulness in your
response.
[questions and followup answers snipped]

I think you misunderstood my purpose in posing the questions.
They were meant for you to consider. If someone were considering
using a scheme like the one you described, I would advise that
they consider these questions and /themselves determine/ what
they thought the answers were. Similarly if I were considering
using such a scheme I would want to evaluate such factors myself.
What someone else thinks the answers are (for their environment)
is not the concern; rather, the concern is what the person(s)
who would actually be using the thing thinks the answers are (in
the used environment). To say this more directly, I'm not
interested in /your/ answers to the questions, I'm interested in
/my/ answers to the questions; to get those answers, I would
want to look at the experience of some independent group using
the proposed scheme in producing an actual deliverable of some
sort, not just an example program done for illustration.

Does that make more sense now?
 
S

Shao Miller

I think you misunderstood my purpose in posing the questions.

That is correct.
They were meant for you to consider.

"You" is perhaps too ambiguous, here. I considered your questions and
shared a couple of answers. Was I mistaken to share them, going
beyond mere consideration?
 If someone were considering
using a scheme like the one you described, I would advise that
they consider these questions and /themselves determine/ what
they thought the answers were.

Certainly sound advice. Part of that determination could include
details from the originator of the scheme, too. That way there are
already some concerns in the pool of awareness to begin with when
beginning the determination process.
 Similarly if I were considering
using such a scheme I would want to evaluate such factors myself.
What someone else thinks the answers are (for their environment)
is not the concern;  rather, the concern is what the person(s)
who would actually be using the thing thinks the answers are (in
the used environment).

This concern snuck up on me, sorry. I really thought you were asking
_me_. Oops.
 To say this more directly, I'm not
interested in /your/ answers to the questions, I'm interested in
/my/ answers to the questions;  to get those answers, I would
want to look at the experience of some independent group using
the proposed scheme in producing an actual deliverable of some
sort, not just an example program done for illustration.

That is a nice strategy. Further code examples from myself might
still lead readers into having a clue about usefulness, or its
opposite. If deemed useful, such deliverables could begin to populate
into existence.
Does that make more sense now?

I don't know. Are you asking _me_? I believe that I understand your
messages' purposes better now.

Thanks again for the constructive feedback.

- Shao Miller
 
Ad

Advertisements

T

Tim Rentsch

Shao Miller said:
[snip

Thanks again for the constructive feedback.

You're welcome. It sounds like you got the gist of
what I was trying to convey on the second go 'round.
I hope it will be helpful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top