This program compiles and runs in C++ but doesn't in a number of different languages, like Java and C#.
#include <iostream>
using namespace std;
void foo2() {
cout << "foo 2.\n";
}
void foo() {
return foo2();
}
int main() {
foo();
return 0;
}
In Java this gives a compiler error like 'Void methods cannot return a value'. But since the method being called is a void itself, it doesn't return a value. I understand that a construct like this is probably prohibited for the sake of readability. Are there any other objections?
Edit: For future reference, I found some a similar question here return-void-type-in-c-and-c In my humble opinion this question isn't answered yet. The reply 'Because it says so in the specification, move on' doesn't cut it, since someone had to write the specification in the first place. Maybe I should have asked 'What are the pros and cons of allowing returning a void type like C++'?
A void function cannot return any values.
Void functions are created and used just like value-returning functions except they do not return a value after the function executes. In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value.
The void type, in several programming languages derived from C and Algol68, is the type for the result of a function that returns normally, but does not provide a result value to its caller. Usually such functions are called for their side effects, such as performing some task or writing to their output parameters.
Void functions do not have a return type, but they can do return values.
We use void function in C language when the function does not return any value/output. Void shows that the funtion returns null value. Originally Answered: Why use void function in c language?
In computer programming when void is used as a function return type, it indicates that the function does not return a value. When void appears in a pointer declaration, it specifies that the pointer is universal. When used in a function's parameter list, void indicates that the function takes no parameters.
void : The data type void actually refers to an object that does not have a value of any type. We have already seen examples of its use when we have defined functions that return no value, i.e. functions which only print a message and have no value to return.
It means “no type”, “no value” or “no parameters”, depending on the context. We use it to indicate that: a pointer does not have a specific type and could point to different types. This is probably the most used context of the void keyword. Here we use it as a return type of a function. Such function does not return a value.
It's because of the possibility of its usage in templates. C# and Java forbid void
as a type argument, but C++ permits it to allow you to write template code like this:
template<typename T, typename TResult>
TResult foo(T x, T y)
{
return foo2(x, y);
}
If void
methods weren't allowed to return a void
expression, this template instantiation would be impossible if TResult
was void
. If that were the case, you would need a separate template definition if you ever wanted TResult
to actually be void
.
For example, remember how in C# there are two sets of generic general-purpose delegates, namely Func<>
and Action<>
? Well, Action<T>
exists precisely because Func<T, void>
is forbidden. The C++ designers didn't want to introduce situations like this wherever possible, so they decided to allow you to use void
as a template argument -- and the case you found is a feature to facilitate exactly that.
(Allow me to write the rest in a pretend-Q&A format.)
But why do C# and Java not allow a similar construct?
First, realize how generic programming is made possible in those languages:
Why pick one approach of implementing generic programming over the other?
Okay, so what would C# and Java need to do to support
void
as a valid generic argument?
I would have to speculate to answer this, but I'll try.
At the language level, they would have to waive the notion that return;
is valid only in void
methods and always invalid for non-void
methods. Without this change, very few useful methods could be instantiated -- and they would all probably have to end with recursion or an unconditional throw
(which satisfies both void
and non-void
methods without returning). So to make this useful, C# and Java would also have to introduce the C++ feature of allowing you to return void
expressions.
Okay, let's assume you have that and now you can write code like this:
void Foo2() { }
void Foo()
{
return Foo2();
}
Again, the non-generic version is as useless in C# and Java as it is in C++. But let's move on and see its real usefulness, which is in generics.
You should now be able to write generic code like this -- and TResult
could now be void
(in addition to all the other types that were already permitted):
TResult Foo<T, TResult>(T a)
{
return Foo2(a);
}
But remember that in C# and Java, overload resolution happens "early", rather than "late". The same callee will be chosen by the overload resolution algorithm for every possible TResult
. And the type checker will have to complain, because you're either returning a void
expression from a possibly non-void
method or you're returning a non-void
expression from a possibly void
method.
In other words, the outer method can't be generic, unless:
What if we went with the first option - make the callee's return type generic and move on?
We could do that, but it simply pushes our problem to the callee.
At some point, we would need some way to "instantiate" some kind of void
instance and optionally be able to receive it somehow. So now we would need constructors for void
(although every void
method could count as a factory method, if you squint) and we would also need variables of type void
, possible conversions from void
to object
, and so on.
Basically, void
would have to become a regular type (e.g. a regular empty struct) for all intents and purposes. The implications of this aren't terrible, but I think you can see why C# and Java avoided it.
What about the second option - postpone overload resolution?
Also entirely possible, but note that it would effectively turn generics into weaker templates. ("Weaker" in the sense that C++ templates aren't restricted to typenames.)
Again, it wouldn't be the end of the world, but it would involve losing the advantages of generics that I described earlier. The designers of C# and Java clearly want to keep those advantages.
Sidenote:
In C#, there is one special case I know of, where binding happens after the validation of the generic type definition. If you have a new()
constraint on a T
and you attempt to instantiate a new T()
, the compiler will generate code that checks whether T
is a value type or not. Then:
new T()
becomes default(T)
-- remember that C# default struct constructors aren't really constructors in the CLR sense.Activator.CreateInstance
is called, which is an indirect constructor invocation using reflection.This particular case is very special because, even though it has completely postponed method binding to the runtime, the compiler can still perform static analysis, type checking and code generation once. After all, the type of the expression new T()
is always T
and a call to something that has an empty formal parameter list can be trivially resolved and verified.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With