Hacker News new | ask | show | jobs
by gpderetta 705 days ago
void is the unit type. The fact that it is not constructible is a wart of the language, inherited from C. It would be easy to fix and would simplify a significant amount of generic code.

A function returning bottom cannot return, yet void foo() {} can. In fact it can even return the result of calling other void functions:

   void bar() {  }
   void foo(){ return bar();}
In generic code void is usually internally replaced by a proper, regular void_t unit type and converted back to void at boundaries for backward compatibility.

  [[noreturn]] void bar(); 
would be a candidate for a bottom-returning function, except that [[noreturn]] isn't really part of the type system.
4 comments

> void is the unit type. The fact that it is not constructible is a wart of the language, inherited from C. > A function returning bottom cannot return, yet void foo() {} can.

Or you could say it the other way, that it is the bottom type, and the fact that it can be used as the unit type for returned values is a wart of the language. Furthermore, void* isn't a pointer of the unit type, it's a type for pointers to undefined/unspecified value types.

nothing is gained by making void a proper bottom type. It would only break existing code. OTOH make void a proper unit type would be backward compatible and actually make the language simpler both from a specification point of view and in practical terms.
I didn't mean that it should be made into a bottom type, even though it sort of looks like it on the surface.

I think the original idea was that void meant "unknown", not "empty" or "non-existent": It was all about whether values could be allocated or not (the wart mentioned above). A plain void variable cannot, but a void pointer can be allocated. For functions, they just reused the keyword to mean "no return value" or "no arguments".

A pointer to the bottom type would make even less sense as an interpretation for void *, since such a pointer couldn't possibly point to any initialized value.
Sorry, I wasn't clear enough: I meant that void is not just a mix of the unit and bottom types, it is also in used for unspecified (unknown actually) types.
I ran into this recently writing some C++20 coroutines. The protocol for delivering values from a coroutine that was previously suspended has two flavors: one for values and one for void. My initial draft just implemented the value version and used a struct VoidTODO {} where void should be.

It's too late now. void pointers are used as a pun to mean "type wildcard." If void were a real thing that could have a size and address, that wouldn't work anymore.

Yes!! Been there done that. Two flavors of EVERYTHING: one to deal with functions that return values; and one to deal with void functions. It's awful.
Void means "it is a syntax error to construct a value of this type". This is not a type that exists in category theory or Haskell. (But similar to the "bottom" type.)

Hence, "void*" - a pointer to something, but it would be a syntax error to derefence this pointer.

In that regard void behaves like any incomplete type. In C and C++ you cannot construct objects of incomplete types nor you can assign through pointers of incomplete types. But you can construct pointers to void and other incomplete types.

Differently to other incomplete types void has some special behaviour: you can declare a function as returning void and return with no arguments is also special cased. You can also cast to void.

A void with proper unit semantics would simply be a complete type instead. The only special case would be return with no arguments implicitly returning a void instance, but that would be pure sugar.

That's a good point. Maybe one could argue that rather than the unit type not being constructible, the wart of C is that functions that return "bot" can still "finish executing without returning".

I would almost rather argue that void is indeed the "bot" type, and a function marked with a void return type shouldn't be said to "return void;" rather we should say that it's an overloaded syntax that means the function has no return value at all. Same for "return bar()" there, that's just a false-friend of the syntax for returning a value, just syntactic sugar for "bar(); return;".