www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Normalize void

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
Suppose I want to create a type to contain either a return value 
or an error, I could probably do something like this:

     struct Result(T, E) {
         bool is_err;
         union {
             T result;
             E error;
         }
     }

This will probably work fine, unless I don't need an error for 
some of the use cases (i.e. I want it to behave more like a 
Nullable). I can't just pass 'void' to 'E', because I can't 
define variable with type void. So I will have to:

     struct Result(T, E) {
         bool is_err;
         union {
             T result;
             static if (!is(E == void))
                 E error;
         }
     }

I hope you can see what I mean here: 'void' is a special case I 
need to explicitly handle in templates. And special cases are bad.

What I want is for 'void' to behave like a normal type. This is 
not a crazy idea. 'void' can be considered as a unit type[0] in 
type theory. Basically, it is a type that can hold exactly 1 
value (so you don't need any storage space to store it). And it 
exists in many programming languages.

D actually already partially have 'void' as a unit type. For 
example:

void a() { return a(); } // returning void in a void function

Why don't we make it consistent across the whole language?

Here is how 'void' would behave if we made it a unit type:

     void a; // fine
     pragma(msg, a.sizeof); // 0
     void b = a; // fine
     writeln(a); // prints something intelligent about void

     struct A {
         void placeholder; // fine
     }
     pragma(msg, A.sizeof); // 1, same as empty struct

[0]: https://en.wikipedia.org/wiki/Unit_type
Jul 10 2018
next sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Tuesday, 10 July 2018 at 09:50:45 UTC, Yuxuan Shui wrote:
 Suppose I want to create a type to contain either a return 
 value or an error, I could probably do something like this:

 [...]
Possible alternatives: * struct Void {}. Takes 1 byte, not as ideal * alias Void = AliasSeq!(). Doesn't work as template argument. i.e. SomeTemplate!Void; // actually become SomeTemplate!()
Jul 10 2018
parent reply ag0aep6g <anonymous example.com> writes:
On 07/10/2018 11:56 AM, Yuxuan Shui wrote:
 Possible alternatives:
 
 * struct Void {}. Takes 1 byte, not as ideal
 * alias Void = AliasSeq!(). Doesn't work as template argument. i.e.
        SomeTemplate!Void; // actually become SomeTemplate!()
What about `void[0]`? It's a proper type. You can declare a field with it. Size is 0.
Jul 10 2018
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Tuesday, 10 July 2018 at 11:37:25 UTC, ag0aep6g wrote:
 On 07/10/2018 11:56 AM, Yuxuan Shui wrote:
 Possible alternatives:
 
 * struct Void {}. Takes 1 byte, not as ideal
 * alias Void = AliasSeq!(). Doesn't work as template argument. 
 i.e.
        SomeTemplate!Void; // actually become SomeTemplate!()
What about `void[0]`? It's a proper type. You can declare a field with it. Size is 0.
Nice!
Jul 10 2018
parent Mr.Bingo <Bingo Namo.com> writes:
On Tuesday, 10 July 2018 at 13:28:42 UTC, Yuxuan Shui wrote:
 On Tuesday, 10 July 2018 at 11:37:25 UTC, ag0aep6g wrote:
 On 07/10/2018 11:56 AM, Yuxuan Shui wrote:
 Possible alternatives:
 
 * struct Void {}. Takes 1 byte, not as ideal
 * alias Void = AliasSeq!(). Doesn't work as template 
 argument. i.e.
        SomeTemplate!Void; // actually become SomeTemplate!()
What about `void[0]`? It's a proper type. You can declare a field with it. Size is 0.
Nice!
How does that solve your original problem? struct Result(T, E) { bool is_err; union { T result; static if (!is(E == void)) E error; } } I thought you didn't want to have to specialize(meaning the static if)? Doesn't seem like passing void[0] really solves that problem since you still might pass void. I think the real solution is simply to never pass void! Then the static if is not needed struct Result(T = void[0], E = void[0]) { bool is_err; union { T result; E error; } }
Jul 10 2018
prev sibling parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Tuesday, 10 July 2018 at 09:50:45 UTC, Yuxuan Shui wrote:
 Suppose I want to create a type to contain either a return 
 value or an error, I could probably do something like this:

 [...]
Breaking changes: void[] x; pragma(msg, x[0].sizeof); // now 0?
Jul 10 2018