August 11

We had two planning sessions in July, one on the 21st and one on the 28th.

Language Editions

Background

I first reported on our new deprecation policy in my June Planning Update. Later, Walter expanded on that in a forum post titled 'Evolving the D Language'. The TL;DR:

  • we will be much more conservative with deprecations
  • Walter is evaluating current deprecations to see if they're unnecessary or causing problems and reverting them if so
  • we should strive to compile obsolete code by default, i.e., features that would otherwise be deprecated, but where possible provide a means to opt-in to warnings about its use (in the form of the -wo switch) rather than taking the opt-out approach of deprecation

These changes are rooted in our new vision statement:

>

To enable the realization of ideas by shifting the way programmers think.

Our approach to deprecations was a hindrance to the realization of ideas and so was not aligned with our vision. The changes are aimed at decreasing breakage and increasing the odds of success when someone tries to compile an older D library with a newer D compiler, goals that will enable the realization of ideas.

The decision

In the face of these changes, how can we continue to evolve the language? That was the big question we set out to answer in our first July planning session.

Átila has mentioned language editions in his talks for DConf Online 2021 and DConf '22. The topic has also come up in recent meetings, most recently in our July monthly meeting. After much discussion in the planning session, we agreed that editions look like the best way for us to maintain backward compatibility while still evolving the language without suffering the hard split of a major version change.

The planning update I published in May listed the three high-level goals we've set ourselves. One of them is to stabilize the language, so we aren't currently implementing new features. We'll revisit these goals down the road and, at some point, we'll add "evolve the language" to the list. Before that day comes, we need to have our policy on language editions in place.

To that end, Átila volunteered to draft a proposal. When he brings it to us, we'll review it and shape it up as needed, then ask for community feedback.

One consequence of this is that DIP 1000 will not be enabled by default until we can do it in a new edition. The warnings about scope parameters, which are errors when DIP 1000 is enabled, will remain behind the -wo switch. Additionally, Dennis is going to see about adding support for filters to -wo, -d, -de, and -dw so that you can, e.g., enable warnings about obsolete code for your codebase and keep it off for dependencies, and shut off deprecation messages for dependencies while keeping them on for your codebase.

New Annotation for Static Constructors

Background

In our June monthly meeting, we discussed the problem that DRuntime sometimes aborts execution of static constructors with a "cycle detected" error when modules with static constructors import other modules with static constructors. There should be a way to prevent that when a constructor is truly standalone. The workarounds Walter always suggests are to either put the constructor in its own module with no other imports or to tag it with pragma(crt_constructor). Adam Ruppe and Steven Schveighoffer insisted that isn't always feasible.

Adam came to our July monthly meeting with a proposal: we should implement a new annotation that users can apply to a static constructor to indicate that it is standalone and should be excluded from cycle detection. The result of that discussion was that Walter asked Adam and Steve to provide example code showing when neither of the suggested workarounds is possible.

In the days after the monthly, I followed up with Adam and Steve. They gave me their example code, and I brought it to the first July planning session.

Steve's example:

__gshared string[string] dict;

shared static this() {
    dict = ["a" : "b"];
}

There are two arguments here: this can't be a CRT constructor because it depends on DRuntime, and arguing that it should go in its own module is a QoL issue---we can make that case for classes when you want private-to-the-class rather than private-to-the-module because the language is working as intended, here it isn't.

Adam's example:

__gshared Object function()[string] factories;

Object build(string s) {
         return factories[s]();
}

mixin template Register() {
         shared static this() {
                 factories[typeof(this).mangleof] = () {
                         return new typeof(this);
                 };
         }
}

This can't be a CRT constructor because of the DRuntime dependency, but neither can it go in a standalone module as it's intended to be mixed into a class.

The decision

The discussion on this topic was not as long as the one above, and almost everyone agreed. It was just a matter of bringing Walter around. And in the end, he came around.

There are a couple of questions remaining:

  • Should it be a pragma or an attribute? Walter favors a pragma (and it's consistent with the CRT pragma). Adam favors an annotation.
  • What should it be called? Walter doesn't want anything negative (e.g., noCycleCheck or skipCycleCheck). standalone is a possibility.

Although this is a new feature, it fits in with our goal of stabilizing the language since it's intended to fix a feature that isn't working as intended. So we can implement it as soon as the details are sorted.

The Second Session

We discussed two topics in our July 28th session and did not reach a concrete decision with either: what to do about std.json and whether the frontend should act like a linter and, e.g., warn about unused imports.

The GC pressure created by std.json came up twice in our July quarterly. Mathis Beer had added a warning about it to the documentation. I wanted to know if we intended to replace the module and whether we should note that in the documentation if so. There was a bit of discussion about whether we could reduce its GC usage without changing its API, and how we can replace it in Phobos v2, but the only conclusive decision was that there's nothing to add to the documentation for now.

Dennis had questions about enabling the compiler to do work normally done by a linter, like warning about unused imports or certain kinds of casts. This took us into a long discussion about what is and isn't possible outside of the compiler's semantic stages (e.g., what an external tool can do vs. what only the compiler can do), and what dmd-as-a-library can and can't do. Walter and Martin are generally opposed to adding this sort of functionality to the front end (Martin adamantly so, though I believe he'd be in favor of plugins). Again, we didn't reach a conclusive decision. The plan for now: Razvan will keep moving on work for DMD as a library. Once that's complete, we can see what it looks like to add this kind of thing to the compiler (maybe even as a plugin) and bring it back to Walter then.

August Planning Sessions

With DConf coming and several of us going into travel mode before then, it's unlikely we'll have a planning session in August after our monthly meeting on the 11th. However, Robert has proposed that we get together at DConf and start discussing a ten-year plan. So far, we've been tackling immediate problems, both small and large, but we haven't begun talking about our long-term plans. He feels it's time we do so. The rest of us agreed.

I want to emphasize that this is just a preliminary discussion to get the ball rolling, so please don't expect us to have a 10-year roadmap ready to go on the other side of DConf. I expect it will take us a while to get this sorted out.