May 08

On Tuesday, 7 May 2024 at 17:44:25 UTC, Paul Backus wrote:

>

On Tuesday, 7 May 2024 at 16:34:52 UTC, Steven Schveighoffer wrote:

>

I don't think this is going to be the case. Consider that without explicitly forwarding, the difficulty is not in preserving refness, but non-refness. If care is not taken (e.g. via using forward), then a non-ref parameter suddenly turns into a ref parameter (implicitly). This is not the case for enum parameters -- enumness is preserved whether it's not an enum or is an enum.

If a single function in a call stack forgets to pass a given parameter by ref, it will be copied. If your code relies on the parameter not being copied (e.g., if it has a disabled copy constructor), this failure to preserve ref results in a bug.

If a single function in a call stack forgets to pass a given parameter by enum, it will be evaluated at runtime. If your code relies on the parameter being evaluable at compile time (e.g., if it uses it as a template argument or in a static if condition), this failure to preserve enum results in a bug.

The two are exactly analogous.

If an entire ref chain is broken by one copy, then the semantics are different. That is, all of a sudden, you aren't affecting the original parameter.

If an entire enum chain is broken by one runtime evaluation, the code does not compile. This is either a loud error, or a silent acceptance that does not affect correctness. Of course, this assumes that the auto-enum in question does not do something drastically different based on enumness.

By example:

void foo(auto ref int x) {
   bar(x);
}

void bar(int x) {
   baz(x); // oops, this does not affect the caller's x
}

void baz(auto ref int x) {
   ++x;
}

// and with enums:
void foo(auto enum int x) {
   bar(x);
}

void bar(int x) {
   baz(x);
}

void baz(auto enum int x) {
   writeln(x); // same whether bar is enum or not, no semantic difference
}

Yes, if baz accepts by enum only, you will get a compiler error. Contrast that with ref, where you get no indication that something is wrong, and it is semantically wrong.

> >

Yes, generic code that wishes to forward enum-ness to another thing must use auto enum to accomplish this. However, comparing to the the current mechanism, things are pretty inferior. Switching from an enum parameter to a runtime parameter involves changing the place where parameters are put. You currently have to remember to create a nested template with an outer template that takes a tuple for this to work correctly (something which I doubt many generic functions do).

Put another way, if the cost of having the convenience of enum parameters is that we must also allow auto enum, I don't think this is a large enough drawback.

The argument here is essentially that it is worth it to make the library author's job more difficult in order to give the library users a better experience.

No, I think it makes both easier.

Consider the case of writef. We have two versions of writef, one which takes a string format via a runtime parameter, and one which takes a string format via compile time parameter.

They have to be called in different ways (burden on the user). You have to write two different functions, and overload them based on template constraints (burden on the developer).

    void writef(alias fmt, A...)(A args)
    if (isSomeString!(typeof(fmt)))
    { ... }

    void writef(Char, A...)(in Char[] fmt, A args)
    { ... }

// vs

    void writef(Char, A...)(auto enum Char[] fmt, A args)
    // note the lack of template constraints needed
    { ... }

It also has the benefit of being easier to explain and easier to document.

>

In general, I agree. But there's a point at which this argument falls apart. If you make the library author's job so difficult that they can no longer write correct code, it is library users who will ultimately suffer.

I don't think this case has been made, even with auto enum.

>

Personally, I think the ref storage class already crosses this line. The vast majority of generic D code does not handle non-copyable types correctly, and the design of ref is 100% to blame for this. Since enum uses the exact same design as ref, I think it's pretty reasonable to assume that it will cause the same kinds of problems.

I can't see how ref is responsible for this. Non-copyable types are difficult to work with in general. Can you explain further?

>

So, when I evaluate this DIP, here's the tradeoff I'm looking at:

  • Pro: more convenient library APIs (e.g., format).
  • Con: more bugs in generic library code.

I have different opinions of these categories.

-Steve

3 days ago

On Tuesday, 7 May 2024 at 15:20:24 UTC, Paul Backus wrote:

>

On Tuesday, 7 May 2024 at 11:23:10 UTC, Quirin Schroll wrote:

>

You’re right in that forward better be mentioned in the DIP. Writing an answer to this post, I found out that not only could forward easily be adapted to recognize enum parameters and handle them properly by leaving them alone, forward actually would handle them correctly today.

Good to know; thanks for looking into this.

However, the main issue here is not forward--it's that in order to write correct generic code with this feature in place, D programmers will forever be obliged to defensively write auto enum auto ref on any parameter they intend to forward (and will have to go back and add auto enum to many of their existing auto ref parameters).

Well, there’s always going to be legacy code that doesn’t interact well with the latest features. It’s unfortunate, but true for every new feature that extends APIs.
What are we gonna do? Never ever extend APIs?

>

Most D programmers already forget to add auto ref to such parameters (see for example the vast swathes of Phobos which fail to compile when used with non-copyable types). Adding an additional thing for them to forget is, like I said, setting them up for failure.

I cannot help but find this argument quite weak. It only concerns library authors. If you write production code and find that a function needs to change and forward ref, you can just change it to do so. Same with enum. It’s the same with attributes.

On the other hand, if a library author doesn’t bother to annotate functions as @safe, the library isn’t usable for SafeD.

>

(Also, auto enum auto ref is quite ugly and "attribute spam"-y, and some programmers will no doubt leave it out of their code intentionally in order to make the code look nicer--as they already do with existing attributes and parameter storage classes.)

The only thing I could imagine doing about this is shortening it to auto enum ref.

3 days ago

On Thursday, 16 May 2024 at 13:59:35 UTC, Quirin Schroll wrote:

>

Well, there’s always going to be legacy code that doesn’t interact well with the latest features. It’s unfortunate, but true for every new feature that extends APIs.
What are we gonna do? Never ever extend APIs?

What we do is, we weigh the costs and benefits of each proposed change, and decide accordingly. I agree that there are cases where introducing incompatibilities with "legacy code" is justified; I just don't think this is one of them.

>

I cannot help but find this argument quite weak. It only concerns library authors. If you write production code and find that a function needs to change and forward ref, you can just change it to do so. Same with enum. It’s the same with attributes.

Given how often people complain that D needs more libraries, I think it's in our best interest to make library authors' lives easier, not harder.

1 2 3
Next ›   Last »