-
Notifications
You must be signed in to change notification settings - Fork 213
Stop allowing void-to-void data transfer? #3410
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
Comments
I use it sometimes. There are times when I don't care for the type of the element. Instead of using |
Interesting! Do you really never need to access those objects? Then why do you iterate over them? ;-) |
Well, I don't. In these cases, I usually want the concept of having a list (reference) or to call one of its fields i.e. If wouldn't mind changing the way I program for a greater good, tho. |
Switch expression cases are another place we allow this today: var y = switch(x) {
_ => print('hello'),
}; |
Switch expressions is a good example: I did not mention the conditional expression void main() {
// Currently: `y` gets inferred type `void`, no error.
// New rule: Error, using "void value" to initialize variable.
var y = switch(x) {
_ => print('hello'),
};
// Currently: OK.
// New rule: OK: Discard the result of a void expression (after one step, but that's OK).
(switch(x) {
_ => print('hello'),
});
} |
@mateusfccp wrote:
OK! Then I misunderstood you. I was just focusing on the But then there's no problem because this issue doesn't say anything about |
This would be another implicit conversion, essentially. Those seem to carry a lot of weight in terms of implementation complexity for relatively little value. I'd be loath to add another unless we felt it was particularly compelling. I'm also disinclined to have code using a concrete type behave differently from the same code where the type is replaced with a type parameter and then instantiated with that same type: void concrete(void param) => param;
T generic<T>(T param) => param;
main() {
print(concrete('hi') as Object);
print(generic<void>('hi') as Object);
} Currently this (admittedly weird) program prints "hi" twice. I think it would be a little weird if it instead printed
Sure, I could see us abolishing this. But it seems relatively low value to do so. We almost certainly have more important things we could be doing. :)
I admit that maybe this my old C programming history showing, but I do sometimes indulge in the luxury of being able to do: void someVoidFunction() { ... }
void someOtherVoidFunction(bool condition) {
if (condition) return someVoidFunction();
// ...
} Instead of: void someVoidFunction() { ... }
void someOtherVoidFunction(bool condition) {
if (condition) {
someVoidFunction();
return;
}
// ...
} There is some interest in making void someOtherVoidFunction(int x) {
var y = switch (x) {
0 => return someVoidFunction(),
_ => x + 1,
};
// ...
} But there is no way to use a switch expression and expand that out to: void someOtherVoidFunction(int x) {
var y = switch (x) {
0 => { // <-- Error. Can't have a block here.
someVoidFunction();
return;
},
_ => x + 1,
};
// ...
} (Of course, allowing blocks in switch expression cases would solve this (#3117). But that's a much bigger issue. In the meantime, allowing void expressions here seems to offer some use.) |
Not necessarily. There is no runtime coercion of the value, it's just not returned. The Which is only needed because the formatter refuses to allow void foo(x) { e; } on one line, even if it would fit. Using I'd personally also disallow My usual recommendation is that every expression with a static context type of |
Sure, it would be like int-to-double, which is another implicit conversion. :)
I feel attacked. :) I have considered allowing
I'd be happy to eliminate statements from the language! :D |
Now you're just messing with me! 😝 (He knows I keep insisting that int-literal-evaluates-to-double-value is not a conversion or coercion, it's just that integer numerals have a context-type dependent semantics. That is, the same syntax have different semantics depending on the context type. But so does the literal
And there is no good syntax to opt you in or out. Which is probably why we have |
The type
void
in Dart works as a compile-time only marker indicating that the given value has no meaningful interpretation, and it should simply be discarded.This works nicely for expressions of type
void
, e.g.,print('Hello!')
, which are accepted with no issues when used as an expression statement, but flagged as an error (not just a warning) if we try to use the value:We allow an expression of type
void
to occur in certain locations which are enumerated in an explicit allowlist.However, several of the allowed positions are special in that they propagate the value which was obtained by evaluation of an expression of type
void
, based on the rule, roughly, that the target has typevoid
as well.Some of these situations occur very rarely (for example, not many variables have declared type
void
, and not many iterables have element typevoid
), but others come up repeatedly (=>
functions are widely used, andvoid
is a rather common return type).This issue is intended to push us in the direction of having fewer situations where such values are propagated.
We could, for example, specify that an
=>
function with return typevoid
returns null, no matter what, and we could eliminate the permission to use the value of avoid
expression to initialize/assign a new value to a variable, or to return such a value.We will still have loopholes, of course. For example,
void
can be the value of a type parameter:A proposal along these lines would be a breaking change (for instance,
return e;
might need to be changed toe; return;
), but I still think that it will be useful to have an issue where this topic is discussed, and we might just do some of these things at some point. For example, I haven't heard any complaints aboutawait print('Hello!')
being an error since Dart 2.12. ;-)The text was updated successfully, but these errors were encountered: