September 27, 2022

On Tuesday, 27 September 2022 at 15:33:35 UTC, Quirin Schroll wrote:

>

It’s another way to get compile-time information into a function that is – notably – syntactically identical to passing run-time information into a function. This is on purpose so the function can potentially react to information passed this way or the other and in the compile-time case, on the information itself, and the user need not care at all.

Hmm okay. The idea of detecting compile-time-ness is really great I think, but I have always figured it's an issue that there's no way currently to have a compile-time parameter and do all the nice checking that can come with that without introducing some level of template bloat. I dunno, maybe it's manageable with what exists today - I'm just now seeing that the checked version of writefln is implemented like this:

    void writefln(alias fmt, A...)(A args)
    if (isSomeString!(typeof(fmt)))
    {
        import std.format : checkFormatException;

        alias e = checkFormatException!(fmt, A);
        static assert(!e, e);
        return this.writefln(fmt, args);
    }

So, you'll get another instance of the function per call, but they would hopefully be inlined away anyway. (Maybe this should be marked with pragma(inline, true)...)

September 28, 2022

On Friday, 23 September 2022 at 15:41:21 UTC, Quirin Schroll wrote:

>

Read the draft here: https://github.com/Bolpat/DIPs/blob/EnumParameters/DIPs/1NNN-QFS.md

Feedback is welcome.

It might be good to start with a simple example. For instance, suppose we have two functions:

void foo(int x) { //do something }
void foo(int x)() { //do something }

We can call foo like foo(x) or foo!x currently. In the first call, x can be a runtime variable or an enum. If x is an enum, then CTFE and compiler optimizations might simplify the resulting code significantly (though it's not always clear how much it will do that). In the second version, each x would generate a new function, resulting in template bloat, but at least as fast as the enum version and potentially simpler code.

You propose to add

void bar(enum int x) { //do something }

and

void bar(auto enum int x) { //do something }

My reading of the DIP is that the first bar is equivalent to the second foo (with template value parameters). The second bar would be like automatically including an overload for void bar(int x) {} along with the first one. So in this sense, you can call bar(x) where x is a runtime variable or a template value parameter.

However, as others have pointed out, what if x is an enum and you don't intend to use it like a template value parameter. This results in unnecessary template bloat. So I'm sympathetic to the argument that this should only work for enums. It limits the usefulness of this feature, but might be a bit more consistent with the language. The question would be whether that will work for your use case with respect to opIndex etc.

In order to better unify template value parameters with normal function calls, it might make more sense to borrow from zig's approach of first class types (though I wouldn't use that as an excuse to get rid of the D template syntax, just as an addition to).

There are a number of typos as well (beyond what is just mentioned so far in the thread) that would need fixing.

September 28, 2022

On Tuesday, 27 September 2022 at 21:02:39 UTC, TheGag96 wrote:

>

Hmm okay. The idea of detecting compile-time-ness is really great I think, but I have always figured it's an issue that there's no way currently to have a compile-time parameter and do all the nice checking that can come with that without introducing some level of template bloat.

The template bloat is unavoidable to some degree. If you want to do Design by Introspection, it’s hard to imagine how to do without.

However, CTFE alone does not instantiate templates. Types do not exist at run-time, but they do exist at half of the compile-time. By that I mean that there’s two compile-times, CTFE and the rest (including e.g. template instantiation), and at the latter, types do exist, but at CTFE, they don’t. Stefan Koch tried to change that when implementing type functions (one thread about it). With those, symbols (including types) would exist and could be inspected and manipulated with CTFE.

September 28, 2022

On Friday, 23 September 2022 at 15:41:21 UTC, Quirin Schroll wrote:

>

Read the draft here: https://github.com/Bolpat/DIPs/blob/EnumParameters/DIPs/1NNN-QFS.md

Feedback is welcome.

>

With auto enum, “compile-time-ness” is determined from argument (cf. auto ref) and queried via a trait.

Huh? I think this is already possible with http://p0nce.github.io/d-idioms/#Is-this-available-at-compile-time-or-runtime?

September 28, 2022

On Wednesday, 28 September 2022 at 15:21:54 UTC, Guillaume Piolat wrote:

>

Huh? I think this is already possible with http://p0nce.github.io/d-idioms/#Is-this-available-at-compile-time-or-runtime?

and, may I say, I don't know of a single instance of anyone doing that.

September 28, 2022

On Wednesday, 28 September 2022 at 15:36:27 UTC, Guillaume Piolat wrote:

>

On Wednesday, 28 September 2022 at 15:21:54 UTC, Guillaume Piolat wrote:

>

Huh? I think this is already possible with http://p0nce.github.io/d-idioms/#Is-this-available-at-compile-time-or-runtime?

and, may I say, I don't know of a single instance of anyone doing that.

TL;DR: Doesn’t work for non-trivial run-time expressions.

You can do this on a type rather easily. Handling values is annoying. The DIP explains it in the Alternatives section: You cannot take run-time values as a template value parameter. You can bind run-time variables with template alias parameters, but then you have to ensure it’s indeed a value (with if (is(typeof(x))) usually) and not a type or some other symbol. Still, you cannot put n+1 into it (unless it can be constant-folded).

Bonus: In D, you have to use the alias parameter even if you want to bind a value as a template value parameter and just infer its type. You have to make sure it’s a value and it’s a compile-time constant. (C++20 has template auto parameters for this.) void f(auto x)() does not parse; void f(T x, T)() doesn’t work, but void f(T)(enum T x) is intended to infer T given f(value). void f(T, T x)() works, but it must be called f!(int, 2).

1 2 3 4
Next ›   Last »