www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Checking if a type is void

reply Stefan Koch <uplink.coder googlemail.com> writes:
Good Day everyone, I know it has been a while since I last posted 
on here.

Did you know that you could check if a type is void without 
having to mention the type void?

And you do it like this

```D
template isVoid(alias X)
{
     enum bool isVoid = is(mixin(`!X`));
}

pragma(msg, isVoid!(int));
```
Check it out for yourself ;)


The reason this is that internally a TypeExpression is created 
and all Expressions defined a `!` operation.
Because all of them are values/ do have init-expressions.

Except for the one type that doesn't which is void.

Which is why you cannot create an init expression for void, and 
that makes the expression `!void` fail during the semantic checks.

Cheers,

Stefan
May 28 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 28 May 2022 at 14:20:22 UTC, Stefan Koch wrote:
 The reason this is that internally a TypeExpression is created 
 and all Expressions defined a `!` operation.
 Because all of them are values/ do have init-expressions.
Reminds me of this example someone posted in the community Discord a while ago: ```d alias T = int*; alias U = typeof(*T); static assert(is(U == int)); ```
May 28 2022
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 28 May 2022 at 14:25:57 UTC, Paul Backus wrote:
 On Saturday, 28 May 2022 at 14:20:22 UTC, Stefan Koch wrote:
 The reason this is that internally a TypeExpression is created 
 and all Expressions defined a `!` operation.
 Because all of them are values/ do have init-expressions.
Reminds me of this example someone posted in the community Discord a while ago: ```d alias T = int*; alias U = typeof(*T); static assert(is(U == int)); ```
At first I didn't see what was unexpected about that. :) But yes that seems to have a similar cause.
May 28 2022
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 28 May 2022 at 14:35:03 UTC, Stefan Koch wrote:
 On Saturday, 28 May 2022 at 14:25:57 UTC, Paul Backus wrote:
 ```d
 alias T = int*;
 alias U = typeof(*T);
 static assert(is(U == int));
 ```
At first I didn't see what was unexpected about that. :) But yes that seems to have a similar cause.
Yes indeed! If you try ```d alias T = void*; alias U = typeof(*T); static assert(is(U == void)); ``` You will the the compiler complaining about void having no value, which indicates that the initValue is indeed the mechanism of operation here.
May 28 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Saturday, 28 May 2022 at 14:37:42 UTC, Stefan Koch wrote:
 Yes indeed!
 If you try
 ```d
 alias T = void*;
 alias U = typeof(*T);
 static assert(is(U == void));
 ```

 You will the the compiler complaining about void having no 
 value,
 which indicates that the initValue is indeed the mechanism of 
 operation here.
Interestingly, there are some operators that cause the compiler to catch the error: ```d alias T = int*; alias U = typeof(T[0 .. 0]); // Error: cannot slice type `int*` ``` So I guess this is just a case of missing checks in the semantic analysis of certain kinds of expressions.
May 28 2022
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 28 May 2022 at 14:43:13 UTC, Paul Backus wrote:

 Interestingly, there are some operators that cause the compiler 
 to catch the error:

 ```d
 alias T = int*;
 alias U = typeof(T[0 .. 0]);
 // Error: cannot slice type `int*`
 ```

 So I guess this is just a case of missing checks in the 
 semantic analysis of certain kinds of expressions.
It open up the question of whether it should actually be an error. Having every time which is not `void` or `typeof(assert(0))` to evaluate to a false boolean doesn't seem to be too bad to me.
May 28 2022
parent Paul Backus <snarwin gmail.com> writes:
On Saturday, 28 May 2022 at 14:47:00 UTC, Stefan Koch wrote:
 It open up the question of whether it should actually be an 
 error.
 Having every time which is not `void` or `typeof(assert(0))` to 
 evaluate to a false boolean doesn't seem to be too bad to me.
It should be an error because the compilier is lying to you that (e.g.) `*T` is a valid expression, when it really isn't. For example, you may write code like the following: ```d void doSomethingWith(int n) {} void example(alias foo)() { static if (is(typeof(*foo) == int)) doSomethingWith(*foo); } void main() { example!(int*)(); } ``` Due to the behavior discussed in this thread, the `static if` condition evaluates to `true`, but compilation fails on the following line: ``` Error: type `int*` is not an expression ```
May 28 2022
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Saturday, 28 May 2022 at 14:37:42 UTC, Stefan Koch wrote:
 static assert(is(U == void));
I'm going to go off on a tangent just to vent: Seeing `typeof(x) == void` doesn't even mean x is a (runtime) expression, because x can be a template: template t {} static assert(is(typeof(t) == void)); This was only recently documented in February. Apparently Walter and Andrei had previously said it should be removed: https://issues.dlang.org/show_bug.cgi?id=15437#c6 https://github.com/dlang/dlang.org/pull/3218 I don't think it makes any sense.
May 29 2022
parent Boris Carvajal <boris2.9 gmail.com> writes:
On Sunday, 29 May 2022 at 13:26:55 UTC, Nick Treleaven wrote:
 On Saturday, 28 May 2022 at 14:37:42 UTC, Stefan Koch wrote:
 static assert(is(U == void));
I'm going to go off on a tangent just to vent: Seeing `typeof(x) == void` doesn't even mean x is a (runtime) expression, because x can be a template: template t {} static assert(is(typeof(t) == void)); This was only recently documented in February. Apparently Walter and Andrei had previously said it should be removed: https://issues.dlang.org/show_bug.cgi?id=15437#c6 https://github.com/dlang/dlang.org/pull/3218 I don't think it makes any sense.
There was some code depending on this behavior that I even had to make `typeof(T.t) == void` for consistency https://github.com/dlang/dmd/pull/12294). Quoting myself from https://github.com/dlang/dmd/pull/12897#issuecomment-883798530) ``` there is an overuse of `void` in the compiler internals, there are many objects whose type is `void` when it could be something else like an `unresolved` or `none` type, having this distinction should help in general. ``` I agree it should be changed, now there are many `traits` to replace its usage. We only need a deprecation period.
May 29 2022
prev sibling parent Boris Carvajal <boris2.9 gmail.com> writes:
On Saturday, 28 May 2022 at 14:20:22 UTC, Stefan Koch wrote:
 ```D
 template isVoid(alias X)
 {
     enum bool isVoid = is(mixin(`!X`));
 }

 pragma(msg, isVoid!(int));
 ```
 Check it out for yourself ;)
Not working: ```D pragma(msg, isVoid!(void)); ``` prints 'false'.
May 29 2022