std.format and uninitialized elements in CTFE

Steven Schveighoffer schveiguy at gmail.com
Sun Dec 8 18:16:29 UTC 2019


On 12/6/19 1:49 AM, berni44 wrote:
> On Thursday, 5 December 2019 at 19:45:27 UTC, Steven Schveighoffer wrote:
>> What is the point of formatting items that aren't initialized? You 
>> would be printing garbage.
>>
>> What if you just initialize the items you wish to print,
> 
> You are on the wrong track... I'm programming inside of phobos. Such 
> questions do not arise there. If the user provides a struct with 
> (partially) uninitialized items std.format has to cope with this 
> somehow. We cannot really answer the question, why the user is doing 
> this, nor can we make him initialize the items before printing.

The normal compiled code works correctly during normal execution. It 
prints garbage. What you are looking to do is do this at compile-time, 
which is not allowed.

Again, just don't do that.

> 
> Ali's example shows, that this is a serious issue. IMHO my example 
> should print `Foo(void)` or `Foo([void, void, void])` with `int[3]`. 
> With that, Ali's example will work.

Ali's example is different, because it's given an *actually initialized* 
structure, not one that is uninitialized, and the compiler complains. 
I'd consider that an actual bug (in Phobos I would guess, not the compiler).

What you want is for CTFE to have some mechanism to deal with 
uninitialized data aside from an error (which is perfectly acceptable).

> 
> For me, the question remains, how to detect (at compile time) if a 
> variable is void. The best I could come up with yet is:
> 
> int a = void;
> 
> static if (!__traits(compiles, a?a:a))
> 
> But I'm not sure if ?: can be applied to all thinkable types.

You are thinking incorrectly about CTFE ;) It's executing an *already 
compiled* function, at compile time. There is no static determination of 
anything at compile-time for CTFE function parameters. This is why the 
__ctfe variable is a runtime variable, and not a compile-time one.

So because you can access the variable at runtime (runtime D doesn't 
reject accesses to uninitialized data, as it doesn't know that has 
happened), it compiles and will try to run in CTFE.

In fact, you can pass it in uninitialized data, and as long as CTFE 
doesn't interpret any code that will read it, it will work.

For example, this works:

```
struct Foo
{
    int i = 5;
    int a = void;
    string toString() { import std.conv; return i.to!string; }
}

import std.format;
static x = format("%s", Foo());
```

It's hard to have discussions about abstract types that obviously are 
not useful. Maybe if you have a more likely example, you can get help 
finding the right course of action.

-Steve


More information about the Digitalmars-d mailing list