From: BGB / cr88192 on

"Colin Paul Gloster" <Colin_Paul_Gloster(a)ACM.org> wrote in message
news:alpine.LNX.2.00.0912241319270.31236(a)Bluewhite64.example.net...
> On Mon, 21 Dec 2009, BGB / cr88192 posted:
>
> |-------------------------------------------------------------------------|
> |"[..]
> |
> |
> |
> |my reasons for using C are varried, although, part of it may be that
> [..]|
> |[..], and also I use
> |
> |some amount of "reflection", which does not work so well with C++
> (mostly|
> |giving the non-standardized name mangling and compiler behaviors, ...).
> |
> |
> |
> |[..]"
> |
> |-------------------------------------------------------------------------|
>
> Hi!
>
> How and why do you use relection in C?
>

how:
piles and piles of code implementing it (this is hardly a small piece of
code);
some use of API's like ToolHlp, DbgHlp, ... (these are provided by Windows
to help implement debuggers). (much of this has Linux analogues, many via
libdl and extensions, ..., but keeping the Linux port alive and well has
been, well, lacking...).

customized in-memory linking code, a custom DLL loader and an x86
interpreter;
a database to manage metadata (shared variable, function, and type
declarations, ...);
an dynamic C cimpiler (more needed for eval and dynamic loading, not so much
for reflection, but it does have uses getting data loaded into the DB);
....

of note, machine code, and plain compiled C, does not, in itself, contain
sufficient information to allow for reflection, rather, it requires a whole
lot of "support machinery" which serves in part to gather and build this
information, and a lot of dynamic code generation to actually be able to
make use of it for anything.


for example, one can realize after writing a C compiler that, for its
internal operation, it generates piles of useful information, but nearly all
of this is lost with the generated code.

a database was then used to capture some of this data, so that data can be
mined from any code or headers which pass through this compiler (going
further, I eventually ended up adding a "dummy mode" to the compiler upper
end, which basically mines info but does not bother generating any code).

the info in the database is then used in conjunction with information in the
run-time linker, mostly to allow accessing variables, dynamically calling
functions, ... (basically, I can do something sort of like the LISP-style
'apply' with C function pointers, including with dynamically-typed
arguments, given limited static<->dynamic auto-marshalling exists).

a downside:
I am more recently using MSVC for building, and this strips symbols/... from
produced PE/COFF images, which hurts the ability of my dynamic code to
access any "non-exported" statically-compiled+linked code (say, in DLL's),
however, in practice this has not hurt too badly (some of this could be
helped if info from the PDB files were used, and it were required that code
always be built with debugging options, but given in MSVC this breaks
optimization, I have not been willing to generally accept this cost).

(when I was building with GCC, it left symbol info in the produced PE/COFF
images, and I would mine this info as well).


another downside:
dynamic C compilation seems nicer in theory, as it can be noted that C does
not compiler "instantly" (nor is my compiler entirely bug-free), which
someone hurts my motivation to compiler the C code at run-time (although,
dependency tracking and object-file caching does help here, since it can
limit re-compiles mostly to dependency-check failures...).

the result is that I end up doing a lot of dynamically generated code in
ASM, which is not a good option either, and I currently lack any good
"middle of the road" language (although, I had considered a wide range of
options, including allowing a C variant which was relaxed some and able to
"see" all of the declarations in the metadata DB without need for explicit
declaration or import, hence "header-free", ...).

similarly, the effort has not been extended to cover C++ for various reasons
(for example, MSVC and GCC have different ABIs, and my framework yet still
another ABI, ...).

(now consider that there is a half-assed Java implementation in the mix,
....).


and, further:
although it is possible to patch functions at runtime, this is ill-advised
with any statically compiled code (EXE and DLL images), since there is
little to say that the patch will actually effect said static code, or that
this patching will not instead crash the statically-compiled app. there are
also some edge cases where this patch will not be properly updated (say if
function pointers exist to the pre-patch version).

a workaround exists, however:
it requires being explicit about patchable functions (kind of defeats the
purpose of patching);
it requires compiling patchable code via my compiler;
the same effect is easily enough done in static land via specialized use of
function pointers (or via COM interfaces).


why:
all this is a harder issue...


sadly, I have since noted that there are many cheaper and simpler ways to do
nearly everything I have done, giving me doubts at times as to whether this
all was a worthwhile effort...

after all, one can hard-code nearly any of this, or address many of these
cases though special-purpose functions or by doing (generally terrible)
things with pointers, ...

I am left also thinking that maybe had all this actually been "designed"
(rather than hacked and extended in a piecewise manner), a much simpler
piece of technology could have addressed all these uses, ...


in some ways, it is sort of like .NET without the bytecode.
(and, hence, no direct binary compatibility between Win32/Linux
x86/Win64/Linux x86-64... or at least apart from using the interpreter...).

any what if one wants interpretation or bytecode, well then I have an
interpreter, which in turn does x86 (actually, this uses a POSIX-derived set
of APIs, and supports multiple processes, sockets, shared memory, ..., but
uses PE/COFF rather than ELF or similar...).

and, in turn, the world visible from the interpreter is not too much
different from that I tried to escape, as, once again, it is largely without
reflection or high-level abilities (although, these could be added as
APIs...).

but, nearly all of my stuff does not work cleanly between disjoint address
spaces, which is, lame...
(although, eval would not be difficult to pull off, since it would just
require sending the object over to the interpreter and linking it there).

instead I am left considering the possibility of something like DCOM, which
is something I initially terribly wanted to avoid...


> With kind regards,
> Colin Paul Gloster


From: Ed Prochak on
On Dec 19, 2:56 pm, William Ahern <will...(a)wilbur.25thandClement.com>
wrote:
> Thad Smith <ThadSm...(a)acm.org> wrote:
> > jacob navia wrote:
> > >http://cacm.acm.org/magazines/2009/5/24646-api-design-matters/fulltext
>
> > > Communications  of the ACM rarely bring something practical.
> > > This is a good exception.
>
> > > It is a good article about API design, and the problems of bad APIs.
> > Agreed.  I plan to distribute the link to others at work.  It makes
>
> A good API emerges from iteration. You really can't know how to make a new
> API work for you until you've used it in various situations. Tweak, use,
> tweak use. Sometimes after two or three iterations you have a really solid
> design, sometimes you need more. A couple of the authors suggestions in that
> paper reflect this dilemmea, with the vain suggestions about documentation
> and separating the caller from implementor.
>
> Iteration is extremely hard to accomplish in a commercial environment with
> other engineers because re-writing code is usually frowned upon, especially
> once others have begun using the interface. (Thus if you separate caller
> from implementor you'll never get the opportunity to change the API; and
> it's foolish to think the first try will be even remotely optimal.)

The rule I try to follow is based somewhat on hardware development.:
throw away the prototype!

IOW, your first iteration is seldom optimal. As long as the project
manager understands that, you are okay.

Ed