July 03

The D Language Foundation's monthly meeting for March 2024 was held on Friday the 8th. It lasted about 90 minutes.

The Attendees

The following people attended:

  • Paul Backus
  • Walter Bright
  • Iain Buclaw
  • Jonathan M. Davis
  • Timon Gehr
  • Martin Kinkelin
  • Dennis Korpel
  • Mathais Lang
  • Átila Neves
  • Razvan Nitu
  • Mike Parker
  • Robert Schadek
  • Steven Schveighoffer
  • Adam Wilson

The Summary

Item 1: ulong string literals and NUL termination

Martin said he'd been working on the new ulong string literals for LDC and wanted to know if they should be null-terminated like normal string literals. Walter asked what he meant, as string literals were always secretly null-terminated.

Dennis asked if the same rule applied to hex string literals, which were what Martin meant. Walter said no. Dennis said internally, it was possible to have hex strings or other arrays being a string expression. The compiler would still allocate a null byte in the data segment even if it were an integer array.

Walter said hex string literals were converted to binary data by the compiler, and asked why you'd want the null byte. Dennis said it wasn't that you'd want it, it was that the compiler was just adding a zero terminator in code generation when it saw a string expression. A string expression didn't have to be a string literal. It could be an array, an import statement, or a hex string literal. Internally, there were multiple ways to create a string expression that wasn't a string literal.

Walter said the implicit null should only apply to actual string literals. Mathias asked if there was a downside to doing it in those other places. Because it was put after the array, it only mattered if you took the pointer. Steve said that was correct. He thought the test should be, "Does the compiler explicitly cast this to a character pointer", in which case it should add the terminator.

Paul said he was pretty sure there was code that relied on the current behavior of the zero terminator being applied to strings generated via CTFE, so he would be wary of changing it. Walter agreed but said those were creating string literals, so the terminator should always be applied anyway.

Dennis said he wasn't sure about that. He thought that sometimes you could create a string from a character array that was still a character array internally. He wasn't sure if the compiler added the terminator in that case.

Martin said there were two special cases he was doing in implementing the new 64-bit hex string literals in LDC. The first one was that he was not zero-terminating them. The second one was that he wasn't going to cache them. All other string literals were mergeable across object files. He thought that because these hex strings were intended to represent binary data, you wouldn't be interested in the null terminator and he assumed they'd be larger than the average string literal. He'd had a quick look at the DMD PR and it appeared as if there were no special cases at all. So in DMD, they were likely still zero-terminated and merged across object files like other string literals.

Walter asked why you wouldn't want it merged if it was going into static data. Martin said he assumed the test would be expensive because he used the string itself as the caching key. He had no idea about the new Unicode tables in Phobos where this feature was used, but he assumed they could be pretty large, like a couple of megabytes or so. In that case, the check would be expensive. He assumed that it would be unlikely that you'd have duplicates of these hex strings across object files.

Walter said that made sense. Martin said his main point was he'd expected a spec change, but that wasn't even mentioned in the changelog. It mentioned that you could cast any string literal to a ulong literal, but the compiler had changed in that the string expression could now have a character size of 8 bytes.

Walter asked if Dennis could take care of that. Dennis said he would.

Item 2: Deprecating range API functions on Nullable

Dennis linked to a PR that Jonathan had submitted but had since closed. The PR deprecated treating Nullable as a range. He wanted to know our opinions about it.

Adam said he and Jonathan had had a long discussion about this the night before. He said he used nullables a lot in C# and loved them. But C# had special operators to use with System.Nullable. People hadn't really use Nullable in C# before those operators came in. For example, when you had a Nullable and it was null, the question then was what should the default value be? And there was an operator to use for that when assigning it. So he had wondered if we could do this in D, and Jonathan had given him a list of reasons of why that wouldn't work in D.

Then they'd had a long discussion about .init. Adam had brought C#'s non-nullable classes and wondered if we could do those in D, but Jonathan had pointed out all the problems we'd have with .init if D had non-nullable classes. For example, if you went into a dynamic array with a non-nullable class, what would it do? It would be like the problems we had when we implemented the disabling of destructors. It would be like, it wasn't an initialized struct, but a dynamic array needed an initialized memory hole.

He said our Nullable wasn't actually a nullable yet. Maybe it was an optional, or just a type, and we got the name wrong. Because we weren't doing the things with it that a nullable could do. So should Nullable be a range? He didn't think so. A nullable was just saying that this data could have a null value attached to it without the data itself being null.

Paul agreed that our Nullable wasn't analogous to that of C# and that it was really an optional, or a type with a misleading name. He thought that in Phobos v3 we should rename it and add an actual C#-style nullable, but that was beside the point for this discussion. As for Phobos v2, he felt that trying to use comparisons to the C# nullable as a guiding principle for its design was of limited utility.

As for whether Nullable should be a range, he was split. He could see merits on both sides. But there was a reasonable case to be made on the grounds of separation of concerns that we shouldn't have types be both ranges and other things. He'd be okay if we wanted to adopt that as a design guideline for Phobos v3. But it wasn't obvious to him that it was a big enough deal to justify breaking Phobos v2 given how many other problems in v2 we'd elected to put off fixing.

Átila said he agreed with maybe everything Paul had said. He said Jonathan had talked to him about this before, and he was also sort of torn because Nullable in Phobos was like an optional type, which was basically a container with zero or one element. So why shouldn't it be a range? That looked like a range to him.

He said that maybe we should distinguish between containers and the ranges they made available. Because you could consume a range. Did that also mean consuming the container? Maybe it would be a good idea going forward that Phobos v3 containers not be ranges, but to return a range.

Timon said he had wanted to make a similar point. Clearly, Nullable or Optional or whatever was a container, and the range interface mutated the range if you popped it. We wouldn't expect to change the underlying static array of a dynamic array when popFront was called. That was what this was essentially doing. So it shouldn't be a range. He didn't know if it was worth a breaking change, but he did believe that making it a range had been a mistake.

Robert said that he was pretty sure that among all of us, he had the most nullable code in production. When he first saw this PR and realized that Nullable had a range interface, it had terrified him quite a bit.

He said there was a wider point: we needed to be less clever. D was too complicated. We were trying to push in too much type theory. He would like the first edition we implemented to be really, really boring. If somebody wanted to do magic... just no. He got a thumbs up from Adam, Walter, and Átila.

Átila said there was also too boring. We didn't want to go full Go. Robert said we should be full Go with templates. He said Go was an awesome language. It was boring, but boring was cool. The vision statement we'd come up with wasn't about writing cool software. We wanted to enable stuff. He said the M8 wrench he owned and the hundreds of M8 bolts he had lying around were boring, but they always worked and the wrench was always the same. Maybe an M10 or an M2 bolt might be nicer, but the M8 was awesome and boring.

Átila said we should make things as boring as possible, but no more boring than that.

Walter brought up strings in Phobos. There were all kinds of templates to check if something was sort of a string or kind of behaved like a string or was a string literal or a string made out of ints, and so on. The way Phobos was now, it was impossible to tell what a template accepted in the form of a string. He thought that was very bad.

Another thing he didn't like about Phobos, and thought this might be a language design issue, too, was having something that accepted both a range and an array. Arrays should be more like ranges and not have this distinction between them. He knew you could import std.array and get the range API for arrays, but he'd been thinking that should be revisited. Maybe the language should be modified to allow empty and popFront to be called on arrays.

Átila said that was easy: just put the array range API in object.d. Walter said he hadn't thought too far along it yet, but he wanted D arrays to implicitly be ranges and not have to explicitly say they were ranges. He thought it would make things simpler to do that. Átila agreed.

Along those lines, Walter had submitted several pull requests to simplify DMD internally. He was trying to follow the rules he'd laid out in his DConf '23 presentation. It should be so simple that everybody thought that anybody could have written it. That was a large goal he had with the DMD codebase: look at a piece of it, figure out what it was doing, and rewrite it so that it was stupidly simple.

Coming back to Nullable, Robert said if there was a push to remove the range interface, then we should also remove the no-argument form of get. That sometims tripped him up. He'd call it without an argument, it would blow up in his face, and he would feel stupid. If it weren't there, he wouldn't feel stupid, and that would be cool.

Walter said if you accidentally did it regularly, the interface was probably wrong. Robert said it was easy to do wrong. Walter said that default arguments should be used very rarely.

Paul said that for the rare cases when you were writing some kind of low-level code or when you'd already done the check separately, there should be a way to access the value of a nullable without checking. But it should probably be named something like uncheckedGet or unsafeGet instead of just get.

Átila agreed, and proffered tryGet. He added it should probably be made @system. Steve thought tryGet sounded correct. Timon proposed getOrDie. Robert said this kind of thing had to hurt to type out. It had to be clear that this was "get with a foot gun". Átila offered prettyPleaseGet.

Addenum: Phobos v3

Dennis knew that Walter didn't like isSomeString or isSomeChar, but said they had made it into Phobos v3. Walter joked that we should kill it before it spawns. Jonathan said it was very much necessary.

Adam said he'd talked with Jonathan at length. They'd been slowly porting traits over together. isSomeString and isSomeChar were the only ones going in for string and char. He said they'd talked about isString and isChar, but he left it for Jonathan to explain his reasoning.

Jonathan said that isSomeString told us that something was a dynamic array with an element type of char, wchar, or dchar, and isSomeChar did the same for characters. They did exactly what you were asking for so that templates that needed to operate on those things could check. Stuff like isAutoDecodableString, isNarrowString, or anything like that, was completely unnecessary and wasn't making it into v3.

Walter asked about a struct that had an alias this pointing at a string. Jonathan said that was an absolute "no". No enums. No implicit conversions. Only things that gave you exactly what you were asking for so that it was clear and you did't end up allowing an implicit conversion or any related bug in your code. You had to explicitly say you wanted the conversion. None of the traits they'd ported over so far passed for enum or alias this. They all gave you exactly what you were asking for from a list of types.

Walter said isSomeString was already wrong, because a string literal or a slice was something different from a string. As a user, he had no clue what isSomeString included. Calling something a string when it was actually a mutable array of char was pedantically incorrect, as a string was immutable. Jonathan said that with the general terminology we'd been using, it would tell you if something was a string or an array of characters. Walter said he agreed, but it was wrong.

Jonathan said the "some" in the name told you it was not specifically string. Walter said his thoughts on this weren't fully fleshed out yet, but he thought the convention should be that "string" referred to an immutable array of char. Anything checking for an array of char should be called "chars", or "charz" if zero-termination was expected. He said that made sense. He thought we should stop combining "string" and "array of characters" in Phobos.

Jonathan countered that most string processing didn't care if the array was mutable or immutable. Walter agreed, but insisted that a mutable array of char was quite different from a string.

Átila said the only reason he could see this type of trait even existing was when you didn't care and all you wanted was a range of const(char). Other than that, "string" should mean string and all the other things should just disappear. If you wanted to deal with UTF16 or 32, then convert.

Walter said he thought that was something different. He said he'd talked with Adam and they had agreed that character array manipulation in Phobos should only operate on char. But that was something different. He just wasn't sure we wanted to call arrays of mutable characters "string" in Phobos.

Átila agreed but said a lot of algorithms won't care and should be able to take an array of mutable, immutable, or constant. Jonathan reiterated that a lot of string processing just doesn't care. Walter said it should be clear from a function's name if it's planning on mutating or if it doesn't care. Átila said his point was that he could see a need for a trait because of this, but he couldn't see any other need for one.

Timon said he'd been wondering if we even needed this and what the actual use case was. He supposed it was what Átila had said: when you wanted to write an algorithm that worked specifically for strings, and the first thing it did was turn it into a range of some sort of character. But did we need that? Couldn't the algorithm just accept the range in the first place?

Paul said that if we did need this for something, then perhaps the thing to do would be to keep the semantics the same but change the name to something like isSomeCharArray, which was more descriptive of what it actually did. Átila didn't think we needed it. We had a constraint right now where we could test if(isInputRange!(r, char)).

Robert said that Phobos v3 should not use template constraints for overloading, because in v2 right now that was hell. There should just be one function. And if we needed different implementations, that one function could be the jump-off point. Otherwise, the error messages were just going to be crap.

Átila said doing the checks inside the function instead of via constraints wouldn't be better. Robert said it would be better because you'd write your static asserts with a message saying why that combination of parameters couldn't be passed to that function. The error messages would be a lot better.

Timon said that may be better pragmatically, but from the point of view of what it meant, it was worse. It would be saying that you could call this Phobos function, but it wouldn't compile. By default, that would be assumed to be an internal error. So maybe what we should strive for would be to make the pragmatics match the ideology somehow. Like, fixing the language so that we could get the pragmatics while doing it the right way.

Jonathan said that for several functions if you were looking to overload, you could have a simplified template constraint at the top level and do more complex stuff internally for the overloads. Then it would be easier to see what was going on. The problem was when we had extra overloads with different numbers of arguments and such to allow various behaviors. Once you did that, you couldn't stick the checks inside, which was why we usually didn't. There were probably places where we shouldn't have done that, and there were probably places where we didn't do that, but where we still overloaded and had constraints when we didn't need to have.

He didn't know how fixable this was in the general case, but he agreed it was something we needed to look out for to simplify what was there so that we didn't have to look at as much template constraint soup. We should probably look at using different names in some cases. We did have some issues where we overloaded on element vs. range, and that had caused some bugs in some cases. Like output ranges accepted both elements and ranges for put, and he'd run into bugs when, for example, trying to put a range in an output range and it went in as an element.

He didn't know if we never wanted functions that accepted both ranges and elements, but we should be thinking about the effects of that. Should we be overloading or using different names? For example, should put instead be putOne for elements and putMany for ranges? That sort of thing.

Walter agreed and said that one way to clear up overload confusion, not only for the user but for the code itself, was to use different names for different purposes. Like appending an element. In the language itself, appending an element and appending an array was overloaded. It depends on the type. That may have been a mistake.

Jonathan said it was also simplified in the language because you always knew you were dealing with an array and not a whole range of things that could match. Walter agreed but said overloads were something that should be used as sparingly as possible. In Phobos, we'd used them eagerly. Too often he couldn't figure out which overload was being instantiated.

Robert said this all made sense from the standpoint of theoretical design and language design, but he saw D as an engineering tool. It was a wrench for an M8 bolt, and we were trying to design a better bolt. He said no, it had to be stupid. Having distinct names was as stupid as we could get, and he liked that.

Timon said he thought it was a very good idea to reduce the number of overloads. One reason that hadn't been mentioned was compile times. When you had a function with a lot of overloads and a lot of template constraints, every time you called it, some of them would get pruned, but for many overloads, you would then instantiate all the templates and all the constraints to check them. That wouldn't be necessary if you just said from the start what you wanted because then everything would just be a hash table lookup in the compiler, which was immeasurably faster. It also made the code easier to read because you wouldn't need to expand all those constraints.

On a side note, he added that he'd copied D's syntax for array concatenation in his language, but he hadn't included the support for appending single elements.

Átila said he thought Timon was right. We should do things right and get better error messages. Maybe we needed facilities in the language to be able to write easier signatures. For instance, it was never the case that someone would forget to implement a virtual function and couldn't figure it out, because the compiler would tell them that they didn't implement it. We didn't have that for compile-time interfaces, and he thought that was what was lacking here.

Robert said that sounded too much like C++ concepts and he didn't want that. Dennis mentioned Rust traits. Átila brought up Haskell type classes. He said that if you wanted to declare that a given type satisfied a particular compile-time interface, then you should be able to get compilation error messages that tell you the reason why it failed.

Timon thought a lot of that would just be better compiler engineering. He agreed that we should be wary of making the type system too complicated, but he thought allowing an error message on a constraint would go a long way.

Paul said that the way templates were type-checked in D was similar to the way code was type-checked in dynamic languages like Python, Javascript, Ruby, and so on. He thought the consensus among programmers in those languages for handling issues arising from type checking was to adopt a strong unit testing discipline. He thought that was the best path forward for D.

He said there was a fork in the road in language design where you could choose to go the template/macro direction or the traits/type classes/signatures direction. D had more or less fully committed to templates at this point. Trying to change our minds on that would add a huge amount of complexity for relatively little gain. But he did think there was a lot we could do to help programmers write better unit tests for their templates, and what people were doing in dynamic languages suggested that would pay off.

Jonathan said that testing was something you had to do quite thoroughly with templates if you wanted things to work. This came up with ranges quite a lot and didn't get done anywhere near enough, in part because the range API allowed too much. There were too many variations. Part of that was autodecoding, and part of it was the reference type stuff that was allowed. He thought that for some of these cases, we should be more strict about what we were dealing with as opposed to letting everything under the sun go through. That would make it easier to write tests and make sure things worked properly.

He also thought that we should be providing testing facilities for some things, ranges in particular, in the form of test types that could be used with user code, if possible. Types that users could employ to test that their code worked with various ranges or behaved properly in various circumstances. We couldn't cover everything, but we should do as much as we could. Non-copyable types, for example. Most people didn't test for those because they just didn't think about it. Having testing facilities available to test for them would make a difference.

Martin said he'd just remembered something regarding Phobos templates he would like to see changed in v3: how predicates were handled. Take filter for example. The predicate there was an alias function. For every lambda you gave it, you ended up with a new instantiation of the template. He'd like to see an overload in Phobos v3 where the predicate wasn't an alias, but a delegate type. A templated one to account for attribute inference.

He added that not only would this be good for compile times, but it would also help eliminate an error that newbies encounter with map and filter needing the instantiation operator, which wasn't necessary for other languages. We needed a compiler improvement to make it work. It was doable already, but it required an explicit delegate signature. Ideally, the compiler would work that out for you. He'd opened an issue about it.

Paul linked to a Phobos v3 discussion about taking predicates as runtime parameters. Steve noted there was a link there to a forum post from Vladimir Panteleev that made a pretty strong case for why we'd want this over alias parameters. He encouraged everyone to read it.

Adam took us back to isSomeString and asked if Walter was okay with what we'd discussed. Walter said we should at least consider changing the name, but we should seriously reconsider if we needed it. He reiterated that with something like that, he didn't have a clue what it was actually accepting. Átila said he still wasn't sure if we needed it.

Adam said he and Jonathan would have to have more discussion about it, as Jonathan knew more about it than he did. He also said it sounded like he needed to add a section to the Phobos v3 design document saying to avoid overloads in function names where possible.

Walter said it should be something you use rarely, not because you couldn't think of another name for something. He thought overloads were great for something like std.write, but for a lot of cases, it seemed to him that they were used because somebody wanted to avoid coming up with a proper name.

Another thing he'd come to dislike was default arguments. Those should be pretty rare. Adam said he'd add a section to the document about default arguments. Átila said he'd be wary about adding rules like that for API design, as it really depended on a case-by-case basis.

Timon noted that there were times when you might realize that a function needed an extra argument for something you needed to do, so you'd add a parameter with a default argument rather than going back to fix all the call sites or refactoring. It was for one specific use case. He'd seen that happen in codebases he'd worked on where people added 15 default args to a function. If you were thinking of the API up front, it was less of a concern.

Robert suggested the thing to do in that case was to pass a struct. You'd add the arguments you needed as fields and pass it in. Then when you needed to add something else, you added it. He said that had worked well for him. He thought we all could agree that if you had 15 default arguments for a function, we'd be having a stern talk with you. This prompted a side discussion about what the max number of args for a function should be and how many a programmer could keep in memory.

Átila then took us back to the Phobos document, saying it was better to have more general guidelines like "avoid allocations" or "avoid exceptions" rather than specifics about what the API should look like. Too much taste goes into that.

Adam said that he came from a very checklist-driven background with his flying experience. We know what the policies are in many cases, and the checklists serve to remind us to check for these things. In our case, the checklists were for the reviewer to go through and say, "Is there something we should be doing to reduce the number of overloads and default arguments?" It wasn't to say that you could never use them, just to make sure you checked to see if there wasn't a better alternative.

Adam said he'd started tagging any Phobos v2 PR with a label that indicated the submitter should check it against Phobos v3 to see if it was something that should be copied over. We were going to keep v2 around for a while, so this was something we always needed to check for.

Steve said that once v3 was released, we shouldn't be allowing PRs to v2 anymore other than bug fixes. Adam said he and Walter had discussed that, yes, and also regression fixes when things stopped building. He said Walter had been very clear that v2 must continue to function.

Adam said there had been discussions in the community about v3 that went beyond what we were planning, and we should probably tighten up the language we use in talking about it. For example, he'd had conversations with people who thought we should keep adding new features to v2, or that we should use v3 as a complete redesign of Phobos. He said he wanted to completely redesign traits by getting rid of them.

Jonathan said we'd then be screwed for templates in general. We needed some of the traits, some weren't necessary, and some just needed to be reworked. We could debate which were which, but without traits at all, or some sort of language change that enabled another solution, everyone would have to implement the same stuff manually anyway. That would be a mess.

Walter said that some of the descriptions for what some of the traits were testing for were incomprehensible. Jonathan said that as he was porting them over to v3, he was being very explicit about the documentation. Not only in the descriptions but also in a lot of examples showing exactly what they did.

As an example, the v2 standard traits were very inconsistent about accepting enums. Some did and some didn't. He thought it was bad practice for them to accept enums in general, as that was an implicit conversion that didn't take place unless you forced it. So you needed to be testing for it and then doing it explicitly so that you didn't do it accidentally. But, in porting things over, he was looking at the implementations to see what they were doing and clearly documenting whether they accepted enums or not.

Jonathan said that clarity of the trait names was always going to be an issue. A name could only get across so much information and could be misinterpreted. So we needed to make sure we had solid trait names. That was another reason to be as explicit as possible about the documentation.

Walter thanked Jonathan and said he was just triggered by isSomeString. Jonathan said we needed that one in Phobos v2 because of autodecoding and whatnot. We wouldn't need it in v3 anywhere near as much. We wouldn't be doing so much overloading on strings because we were going to focus on arrays of char rather than dchar. Whether we kept it in v3 or not, it wouldn't be necessary for Phobos.

Timon noted that some traits, like hasDestructor, had to accept enums. Jonathan agreed, but in cases like that, the trait was testing only on the specific type it was given, isSomething or hasSomething, not on what the type could be converted to. So for those cases, the documentation had to be very clear that this trait accepted enums and why.

Paul added that it wasn't just the Phobos traits that had the problem with implicit conversion of enums, but also the built-in __traits, like isIntegral and isFloatingPoint. He thought that should be tightened up in a future edition of the language.

Steve said if we were simplifying traits, we should look at getting rid of things that were just wrappers for simple things. For example, we could drop isDynamicArray because we had an is expression to do the same thing. We could also get rid of things that had been superseded by built-in traits and were now just a shell calling out to the built-in.

Jonathan said there were definitely some that he wasn't porting over. Like isBool. This one tested whether something was a bool and whether it was an enum. There was no point in porting that over, as all you needed to do was to check if something was a bool using an is expression. But in other cases, having the named trait was going to be a lot simpler for folks to remember. isDynamicArray was more obvious and memorable than the alternative is expression that did the same thing.

He said he'd been going through and porting traits over one by one as necessary for the tests. At the end, there would be a list of things he didn't port because he decided it didn't make sense to port them. We could then go through and decide if they needed to go in or not. And in some cases, like isSomeString, if everyone decided, "we don't like that", then we could rip it out. He was keeping the PRs small so they were easy to review for anyone who wanted to look at them.

Steve said that minimal was better. Once a trait was in there, it was in there and we'd be stuck with it. He said that regarding the simple traits like those replaceable with an is expression, Dennis had brought up a good point in the chat that you couldn't pass an is expression or a __traits call to a template. That was another thing to think about.

Razvan noted that he'd asked Andrei a few years ago about those simple kinds of traits. Andrei had told him that people shouldn't be calling __traits directly, even in cases like isConst or isImmutable, because it made the code look nicer. Razvan brought that up because he thought that was the reason they'd been added, but he didn't agree with it.

Walter said that actually predated Andrei. It had come about because he couldn't think of a good syntax for traits. So he'd settled on something deliberately ugly, __traits. The idea was that you'd then put a pretty face on it in Phobos. Maybe the thought had outlived its usefulness because people seemed to like them. That was something we could certainly revisit in the Phobos redesign.

Dennis said maybe people preferred __traits because they didn't like importing std.traits to use them. Walter said another nice difference was that you weren't adding overhead with the built-ins. The Phobos traits, as templates, came with overhead.

Walter said another thing he'd wanted to bring up with Jonathan was the nomenclature of "dynamic arrays" vs. "slices". Back when he'd added dynamic arrays to D, he hadn't been familiar with the usage of "slice". He hadn't seen it used much. These days, you saw it pretty often out in the broader programming community. We should consider our usage of the terms. People now would know what they were, except when they expected a dynamic array that was growable and shrinkable. So we needed to be consistent in our terminology: if it was expected to be appended to, it was growable and shrinkable, then it was a dynamic array; otherwise it was a slice.

Jonathan said the problem was that there was no difference as far as the types went. Walter said that was correct. It was too bad we couldn't encode that somehow in the type, but we could at least signal the difference in the nomenclature. Martin agreed. In his mind, a dynamic array had always been a slice backed by the GC.

Regarding the overhead of templates vs. __traits, Martin brought up an issue they'd encountered in the Symmetry codebase a couple of years ago. The Unqual template was getting instantiated something like a million times. Lots and lots of duplicates. Consider that each instantiation was 100 bytes, probably more, but for the sake of example, consider a million instantiations x 100 bytes. It wasn't just Unqual, but other stuff as well. The solution was to replace Unqual with an is expression.

Unfortunately, syntax-wise that was much longer than just using Unqual. So maybe there was a way we could treat some of these std.traits templates as built-ins. They didn't have to live in Phobos. They could live in DRuntime.

Walter said the way to do that was to have the compiler recognize the template and not instantiate it, but just return the result. He'd done that for a couple of the templates. Unqual sounded like a good candidate for that. Then it would still look like a template, but it wouldn't have the cost of a template anymore.

Razvan said that there was always this thought that if something was in Phobos and was being used in Phobos, then we needed to keep it. But we didn't need to consider that when deciding which Phobos traits to keep. We could always just use __traits and is internally. But for the users, there was always a compromise between convenience and performance. Many users might prefer the convenience of the standard traits. So we could use __traits internally but still offer the standard interface.

Jonathan reiterated that for now, he was only porting over the things that Phobos needed for the tests. When he was done with that, then we could decide to replace them internally with __traits or is expressions, and decide whether or not to keep them in the API and which of the remaining ones to port over.

Razvan suggested that another way to look at it was that if some __traits were useful, then we should consider prettifying them and making some extra syntax for them to become first-class citizens. If it was a feature, it was a feature. He didn't see a point in encouraging people to use wrappers for them.

Átila said that Razvan's comments made him think that a good guideline for Phobos v3 would be to minimize interdependencies. Adam agreed. He said he'd add something like that.

Conclusion

To wrap things up, I asked everyone if I should schedule a Phobos v3 planning session. Everyone said yes. We held that on March 16th. This was followed by a quarterly meeting on April 5th and our next monthly on April 12th.

And now the usual reminder: if you have anything you'd like to bring to us for discussion, please let me know. I'll get you into the earliest monthly meeting or planning session we can arrange. It's always better if you can attend yourself to participate in the discussion of your topic, but if that's not possible, I can still put the item on the agenda without your presence with a bit of preparation.