A full chapter is dedicated to dynamic type checking.
If that isn't acceptable for your project, don't use it. Successful languages that don't have compile time checks, show that this problem is irrelevant.
The argument is wrongheaded. Implementations of dynamically typed object systems in C do not benefit from using void * all over the place instead of a typed object * pointer.
C itself isn't dynamic and it behooves you to use it as safely as possible if you don't want your dynamically typed framework to fall apart due to easily avoidable bugs.
Whereas you can have dynamic checking which tells you that some object * pointer is a cons cell, vector, string or whatever, if you use void * instead, the type check itself is threatened with undefined behavior:
object *stringp(object *obj)
{
if (is_heap_object(obj) && obj->typecode == TYPE_STR)
return t_obj;
return nil_obj;
}
// ..
{
int x;
if (stringp(&x)) ... // compile-time error!
}
If stringp has the signature
void *stringp(void *obj);
then there is no compile time error; &x happily passes into the function. Moreover, the function has to do an ugly conversion to recover a typed pointer so it has to use it.
void *stringp(void *obj_in)
{
object *obj = obj_in; // cast needed here in C++
if (is_heap_object(obj) && obj->typecode = TYPE_STR)
Dynamic typing is a high level feature that is boostrapped from static typing (whether that typing is checked by a compiler or not!) Static typing means that a given piece of code working on a given piece of data correctly uses that data. For instance if we write assembly code which extracts the bottom three bits of a word, and treats that as a type tag, that is static typing: it's a static fact of the program that that code operates on data with a three bit type tag, and if it is given something else by accident, like a floating-point value without a type tag, it will misbehave.
In short, something has to be rigid at the bottom-most layer. C has enough type muscle to help with that quite a bit without getting in the way too much.
C itself isn't dynamic and it behooves you to use it as safely as possible if you don't want your dynamically typed framework to fall apart due to easily avoidable bugs.
Whereas you can have dynamic checking which tells you that some object * pointer is a cons cell, vector, string or whatever, if you use void * instead, the type check itself is threatened with undefined behavior:
If stringp has the signature then there is no compile time error; &x happily passes into the function. Moreover, the function has to do an ugly conversion to recover a typed pointer so it has to use it. Dynamic typing is a high level feature that is boostrapped from static typing (whether that typing is checked by a compiler or not!) Static typing means that a given piece of code working on a given piece of data correctly uses that data. For instance if we write assembly code which extracts the bottom three bits of a word, and treats that as a type tag, that is static typing: it's a static fact of the program that that code operates on data with a three bit type tag, and if it is given something else by accident, like a floating-point value without a type tag, it will misbehave.In short, something has to be rigid at the bottom-most layer. C has enough type muscle to help with that quite a bit without getting in the way too much.