Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full void type, including support for use in generics #3194

Closed
appgurueu opened this issue Jul 5, 2023 · 3 comments
Closed

Full void type, including support for use in generics #3194

appgurueu opened this issue Jul 5, 2023 · 3 comments
Labels
feature Proposed language feature that solves one or more problems

Comments

@appgurueu
Copy link

Proper "void" (zero-memory) types (the empty struct in Go; the empty tuple, also called "unit" in Rust) are extremely useful when you want to express a simpler data structure in terms of a more powerful one with zero overhead.

The prime example of this is implementing Sets in terms of Maps: A Set<T> is effectively just a Map<T, void>. You usually want your compiler to optimize the void type out completely (e.g. through monomorphization), such that you waste no memory and time on it.

Without a proper void type, you either need to waste time and space for unnecessary values, such as using bool instead of void and setting the values to a constant true/false, or you need to duplicate your code and remove all instances where the values are being used, effectively performing the monomorphization "by hand".

Proper metaprogramming (such as Zig's powerful comptime) poses a viable (though generally more cumbersome) alternative to a void type. This seems to be in the works?

See also dart-lang/sdk#2231. To answer the questions posed there:

What about a method that takes T as an argument? What does this mean if T = void?

void variables and arguments should only have one value: void - thus the argument would just be a constant void

What is List?.

The list would be a list of contant voids. Since voids take no memory, the List would need no memory except for storing its length. Getting elements would return constant voids, adding elements would only modify the length. Effectively the list would pretty much degrade to an awkward counter. This isn't terribly useful; programmers will always be able to use features for nonsense however.

And it does come in handy if you're implementing B-Trees, where you might want to maintain a list of values for a B-Tree based map: To implement a set in terms of this map, you'll have to set V = void, thus this list of values will become a list of voids. Ideally, to make this list of voids take zero memory, Dart would have to provide an array type where the size is known at compile time, like Go's arrays.

@appgurueu appgurueu added the feature Proposed language feature that solves one or more problems label Jul 5, 2023
@mateusfccp
Copy link
Contributor

It seems you want a singleton type (also called unit type). In Dart, void is (one of the) top type. This means that turning it into a singleton type would change the type system by a lot.

A singleton type, on the other hand, could be introduced without many hassles, AFAIK. I don't know however, how it would fit in the Dart's current type system, as Dart already has a singleton type, which is Null. Null has a single possible value, which is null.

IMO we already have a lot of confusion with top types (we have dynamic, Object? and void[with some limitations]), so having two singleton types doesn't seem like something positive to me.

(Diverging a little, I would rather go in the direction of dropping void and dynamic entirely, but that's another discussion.)

I am not sure how the compiler treats Null, so I can't say if it is completely optimized out.

@appgurueu
Copy link
Author

Thanks for the answer. I wasn't aware of the Null type and would intuitively have expected void to act as a singleton type. This is indeed confusing and perhaps void should be dropped (in favor of Null?) as you suggest.

Might make a follow up issue on arrays with comptime size and monomorphization when I get to implementing my B-Trees :)

@eernstg
Copy link
Member

eernstg commented Jul 6, 2023

@appgurueu, as others have already mentioned, the meaning of the type void in Dart is very different from the zero-memory model that you took as the starting point.

You might want to take a look at the section '20.9 Type Void' in the language specification. (Note that the updates to include null safety are under review, so the link I just mentioned refers to the language specification that specifies the language before null safety. However, that doesn't make much of a difference in this particular section.)

The main point is that an expression of type void in Dart is an expression whose value should be discarded. It is not because there is no value—Dart avoided introducing the notion of a 'procedure' in order to avoid having two kinds of computational abstraction, which would duplicate the size of the language in many ways. So every function call returns a value (or it throws, or it runs in an infinite loop, but it doesn't just return without a value).

The returned value is a perfectly valid object. It is null in most cases, but it could be anything. The point is that the type void is used, say, as a return type of a method, in order to indicate that this method does not return an object which is useful or meaningful for any purpose. If you're using it then you misunderstood something (or you know what you're doing, and it's a very special exception). Consequently, it is a compile-time error to use the value of an expression of type void (further details about this are given in the previously mentioned section in the language specification).

The potential ability to detect that a particular type carries no information and generate special-cased code that avoids allocating any memory for any such non-informative entity is basically concerned with monomorphization, cf. dart-lang/sdk#52722.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems
Projects
None yet
Development

No branches or pull requests

3 participants