|
|
Log in / Subscribe / Register

Void is surprisingly useful.

Void is surprisingly useful.

Posted Sep 10, 2026 9:52 UTC (Thu) by alx.manpages (subscriber, #145117)
In reply to: Void is surprisingly useful. by NYKevin
Parent article: Stabilizing Rust's never type

Indeed, this API lets you write malloc_T(42, void). It's not allowed in the ISO C dialect, because sizeof(void) is not valid there. But in GNU C, sizeof(void)==1, and thus this is perfectly allowed.

alx@devuan:~/tmp$ cat malloc.c 
#include <stdlib.h>

#define rvalue(lv)          ((void)0, (lv))
#define typeof_typename(T)  typeof(*(typeof(T) *){_Generic(0, T: NULL, default: NULL)})
#define mallocarray(...)    reallocarray(NULL, __VA_ARGS__)
#define malloc_T(n, T)      rvalue((typeof_typename(T) *){mallocarray(n, sizeof(T))})

int
main(void)
{
	void *p = malloc_T(42, void);

	/*
	 * The memory in 'p' doesn't have an effective type yet at this
	 * point.  This is useful for example for creating a memory pool
	 * from which to use memory later.
	 */

	int *i = p;
	*i = 7;

	/*
	 * The first byte of the pool now has an effective type of
	 * 'int'.  The rest remains without effective type.
	 */

	free(p);
}
$ gcc -Wall -Wextra malloc.c 
$


to post comments

Void is surprisingly useful.

Posted Sep 10, 2026 9:53 UTC (Thu) by alx.manpages (subscriber, #145117) [Link]

	/*
	 * The first byte of the pool now has an effective type of
	 * 'int'.  The rest remains without effective type.
	 */

Oh, well, I meant the first 4 bytes, of course. :)

Void is surprisingly useful.

Posted Sep 11, 2026 22:29 UTC (Fri) by NYKevin (subscriber, #129325) [Link] (1 responses)

Not sure I would characterize that as an "optional" type parameter. I would maybe call it "GNU C decided to make void act more like a real type, and less like the absence of a type." Anyway, if you're going to give examples in GNU C, you should specify. ISO is the standard dialect (GCC's out-of-the-box behavior notwithstanding).

Of course, there has to be some allowance for special cases where you don't need multiple implementations, because you could always write a function that does not actually use its type parameter. But my point is that in the general case, where you may want to write arbitrary code, you do face a combinatorial explosion. There might happen to be a few special cases where it's not strictly necessary... but Rust in particular is not a fan of this sort of thing.

In Rust (unlike C++), generic definitions have to be valid for all possible choices of parameters, not just for the particular invocation(s) that happen to appear in your project. This is essential for backwards compatibility. If someone calls into your function in version 1.0 with a given set of generic parameters, then that same set of parameters ought to work in version 1.1 (assuming you follow semver or something like semver). Rust upholds that guarantee without forcing you to test all possible (or all "reasonable") combinations of parameters manually, because it does type checking before the generics are monomorphized. By the time parameters are actually substituted, we already know that the resulting code will compile. And you know that you're backwards compatible as long as you didn't change the signature (which includes information about which types are "allowed" to be used as type parameters).

So now you can see the issue: If we want to allow for "optional" type parameters in Rust, we need to fit them into the type checking scheme. At that point, it is a lot easier to say "OK, we're promoting these empty values to full types and giving them completely regular type-level semantics" than it is to say "OK, we're going to litter the generic type logic with dozens of special cases scattered all over the place just in case a type parameter turns out to be empty."

Void is surprisingly useful.

Posted Sep 11, 2026 23:25 UTC (Fri) by alx.manpages (subscriber, #145117) [Link]

> Anyway, if you're going to give examples in GNU C, you should specify. ISO is the standard dialect (GCC's out-of-the-box behavior notwithstanding).

I say it now. ISO C is like speaking standard Latin: nobody does it, and nobody ever did (except maybe a few Romans, during a few years, and maybe neither). It's good as a guideline on which to base dialects, not as an actual dialect meant to be directly useful. Very few programs (none that are non-trivial?) are strictly conforming to ISO C (and even less to ISO C90).

> But my point is that in the general case, where you may want to write arbitrary code, you do face a combinatorial explosion. There might happen to be a few special cases where it's not strictly necessary...

I write a lot of type-generic code using GNU C23, and only have a few places where I've had to duplicate code; they are the special case, IME. We're working to improve the language in ways that those special cases may not be needed in the future.

> but Rust in particular is not a fan of this sort of thing.

I don't write any Rust, but this seems consistent with what I've heard, and with the little Rust I've read: it tends to be more verbose than C.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds