If Rust follows Scala then `()` is not the empty tuple, but rather Unit (void in C*).
If Rust follows Scala then `()` is not the empty tuple, but rather Unit (void in C*).
The empty tuple:
scala> val empty = Tuple1(())
empty: (Unit,) = ((),)
vs. Unit: scala> val empty = ()
empty: Unit = () trait Foo {
type ErrorType;
fn bar() -> Result<u8, Foo::ErrorType>;
}
How would you specify that your type implements Foo in such a way that bar() cannot return an error? If you were to implement it using the empty tuple (unit), like this, it could actually return an error: struct Abc{}
impl Foo for Abc {
type ErrorType = ();
fn bar() -> Result<u8, ()> {
Err(()) // oops, we don't want to be able to do that!
}
}
Instead, you can use Void here: enum Void{}
struct Xyz{}
impl Foo for Xyz {
type ErrorType = Void;
fn bar() -> Result<u8, Void> {
// No way to create a Void, so the only thing we can return is an Ok
Ok(1)
}
}
Aside from the obvious power to express intent (can we return an error without any information attached, or can we not error at all?), this would allow an optimizing compiler to assume that the result of Xyz::bar() is always a u8, allowing it to strip off the overhead of the Result: fn baz<F: Foo>(f: F) {
match f.bar() {
Ok(v) => println!("{}", v),
Err(e) => panic!("{}", e)
};
}
...
baz(Xyz); // The compiler can notice that f.bar() can never return a Result::Err, so strip off the match and assume it's a Result::Ok
A super-smart compiler would even make sure it's not storing the data for "is this an Ok or Err" in the Result<u8, Void> at all.Finally, similarly, you can specify that certain functions are uncallable by having them take Void as a parameter.
The question here was Unit vs empty tuple.
Up-thread was the question of whether C "void" is more like S/H/R Unit or S/H/R Void.
> If Rust follows Scala then `()` is not the empty tuple, but rather Unit (void in C*).
The implication is that () == Unit == void. The empty tuple and unit are essentially equivalent aside from name, void is something else.
In truth, C void is not exactly either Void or Unit. Like Void, you can't exactly make one... but you can call functions declared to take it and write functions that return it, and really it just means "I have no information to pass" - which is more like Unit.
However, () and Unit are.
enum Void{}
fn foo(v: &Void){ ... }
let bar : Void;
fn abc() -> &Void{ ...}
fn xyz() -> Void{ ... }
You can't create a Void, and you can't cast to it either - it's not a bottom type. So you can't put anything in bar. And as a result, you can't create a reference to a Void, so you can't call foo. And abc and xyz just can't be implemented in the first place.On the other hand, you can do all of these just fine:
fn foo(v: ()){ ... }
fn bar(v: &()){ ... }
...
let v = ();
bar(&v);
foo(v);
The fact that you can create and use an empty tuple as a value shows that it is not equivalent to Void.(All statements here are made within the safe subset of the language - unsafe allows access to intrinsics that would allow a Void to be made, and a reference to Void.)