April 08, 2020
On Wednesday, 8 April 2020 at 09:48:25 UTC, Stefan Koch wrote:
> On Wednesday, 8 April 2020 at 09:11:45 UTC, Dennis wrote:
>> On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:
>>> When existing the language is perfectly able to express (only runs at ctfe).
>>
>> assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
>
> The only reason why I used assert (__ctfe) not static assert (__ctfe) is because that's impossible to express.
> since __ctfe is a magic runtime variable that's hardwired to be zero in the non-ctfe case.

This may be a naive suggestion, but how hard would it be to make version(ctfe) work?

version (ctfe) string generateMixin(...) { ... }

Using version means you would be able to know earlier whether a function is ctfe-only, but I'm not sure how you could propogate that information through the rest of semantic-analysis and what effects that could have.

April 08, 2020
On 4/8/20 3:04 PM, Steven Schveighoffer wrote:
>         foo(0);

Ugh, that should have been foo();, forgot to edit that.

-Steve
April 08, 2020
Am Wed, 08 Apr 2020 15:07:32 +0000 schrieb Petar Kirov [ZombineDev]:

> ---------------------------
> 
> In this way we tell the compiler to compile the exported function in `bar` as well as any other functions that they may call.

Thanks for taking the time to write such a detailed answer. I think I'll have to spend some more time thinking about this to convince myself that it really covers all cases.

Anyway, a very interesting idea.

-- 
Johannes
April 08, 2020
Am Wed, 08 Apr 2020 19:16:15 +0000 schrieb Jonathan Marler:

> On Wednesday, 8 April 2020 at 09:48:25 UTC, Stefan Koch wrote:
>> On Wednesday, 8 April 2020 at 09:11:45 UTC, Dennis wrote:
>>> On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:
>>>> When existing the language is perfectly able to express (only runs at
>>>> ctfe).
>>>
>>> assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.
>>
>> The only reason why I used assert (__ctfe) not static assert (__ctfe)
>> is because that's impossible to express.
>> since __ctfe is a magic runtime variable that's hardwired to be zero in
>> the non-ctfe case.
> 
> This may be a naive suggestion, but how hard would it be to make
> version(ctfe) work?
> 
> version (ctfe) string generateMixin(...) { ... }
> 
> Using version means you would be able to know earlier whether a function is ctfe-only, but I'm not sure how you could propogate that information through the rest of semantic-analysis and what effects that could have.

I'd guess very hard. To be consistent with the rest of the language, you then have to support this:

void foo()
{
    version (ctfe)
    {
    }
    else
    {
    }
}

You can end up with two completely different function implementations. And you can do this at top-level as well, where you have the same function in version(ctfe) and in the else block.


Maybe you can somehow cheat and simplify this. But in the most general case, you'd have to keep two versions of the AST of each function.

-- 
Johannes
April 08, 2020
Am Wed, 08 Apr 2020 09:26:36 -0400 schrieb Steven Schveighoffer:

> 
>> My primary fear here is that the current implementation checks the function too late in semantic and therefore such checks (or the "ensure no non-ctfe function calls ctfe-only functions" check are much more difficult to implement than they should be. Using a pragma or attribute would easily solve this.
> 
> This is a legitimate concern. Indeed, it might not fix this issue just to not emit the code to the binary.
> 
> -Steve


I've posted a proof-of-concept PR using pragma(ctfe) here:
https://github.com/dlang/dmd/pull/11014

Unlike the `assert(__ctfe)` check, this is done very early in the semantic analysis. I added support to bypass all -betterC checks I could find in the DMD source code. If one is missing, it should be trivial to add. I've also added examples to the tests in the PR.

I also tried to backport the commit which introduces the betterC bypass to Stefan's PR. But as expected it does not work, as the assert detection is done too late. I'm not saying that we must go for pragma(ctfe), but whatever implementation we merge, it should at least support those tests as well. Especially considering the pragma implementation is also way less complex.


Another thing we could think about is how to handle this code:

@nogc:

pragma(ctfe)
string mixinHelper2(string a)
{
     return "int " ~ a ~ ";";
}

void main() @nogc
{
     mixin(mixinHelper("a"));
}


I'd probably disable nogc checks in ctfe-only functions for convenience. But I guess that is debatable.

-- 
Johannes
April 08, 2020
On Wednesday, 8 April 2020 at 20:07:49 UTC, Johannes Pfau wrote:
> Am Wed, 08 Apr 2020 15:07:32 +0000 schrieb Petar Kirov [ZombineDev]:
>
>> ---------------------------
>> 
>> In this way we tell the compiler to compile the exported function in `bar` as well as any other functions that they may call.
>
> Thanks for taking the time to write such a detailed answer. I think I'll have to spend some more time thinking about this to convince myself that it really covers all cases.
>
> Anyway, a very interesting idea.

Thanks! I do realize that D compilation is a way more complicated process than my simplified model. My idea needs to be better formalized and to endure more scrutiny ;)
April 08, 2020
On Wednesday, April 8, 2020 3:11:45 AM MDT Dennis via Digitalmars-d wrote:
> On Wednesday, 8 April 2020 at 08:42:52 UTC, Stefan Koch wrote:
> > When existing the language is perfectly able to express (only
> > runs at ctfe).
>
> assert(__ctfe) does not express that you STATICALLY know it only runs at ctfe, it is a RUNTIME error and it is impossible to statically decide whether the function may actually get called outside ctfe context.

Sure, but since you're asserting that it should never run except during CTFE, turning that into a compiler or linker error shouldn't be a problem. It's about as clear a case as you can get where the compiler can effectively turn a runtime condition into a compile-time one, because it has enough information to do that optimization, and if assert(__ctfe) is used where it shouldn't be, then it will just result in an error when compiling/linking your program instead of at runtime. Insisting that the compiler not do that optimization doesn't really buy us anything, and having it do that optimization could allow us to reduce compilation times in code with a lot of CTFE-only functions.

It would arguably be cleaner if __ctfe were done in a way that it were a static condition rather than a runtime one (and thus static assert could be used instead), but that's not how it works, and from what I understand of how CTFE in general works, it's highly unlikely that that will ever change.

- Jonathan M Davis



April 08, 2020
On Wed, Apr 08, 2020 at 05:45:43PM -0600, Jonathan M Davis via Digitalmars-d wrote: [...]
> It would arguably be cleaner if __ctfe were done in a way that it were a static condition rather than a runtime one (and thus static assert could be used instead), but that's not how it works, and from what I understand of how CTFE in general works, it's highly unlikely that that will ever change.
[...]

Yeah, static assert is run at template expansion time, which comes before CTFE, so __ctfe cannot be evaluated by static assert:

	https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time


T

-- 
WINDOWS = Will Install Needless Data On Whole System -- CompuMan
April 09, 2020
On Wednesday, 8 April 2020 at 10:47:07 UTC, Stefan Koch wrote:
> A language which only allows you to express bubble-sort may have a good reason for that limitation.
> Though I suspect it would come down to religious believes in mathematical concepts.

Let me be clear in case you're implying my critique is for the sake of satisfying some mathematical principle.

I'm objecting this because *actual D users* constantly complain about D garnering more and more half-baked features that don't integrate well with the rest of the language, and this is like the epitome of that. It does not work at all with `version`, `mixin`, constant folding among others.
April 09, 2020
On 08.04.20 12:27, Dennis wrote:
> 
> What now, another hack? Or should we finally think of something to make __ctfe work with `static if` / `static assert` proper?

It's obvious how to make that work, but is it really worth the effort and compile time overhead? You'd have to perform semantic analysis twice for each function.