D Language Foundation March 2024 Monthly Meeting Summary

Mike Parker aldacron at gmail.com
Wed Jul 3 17:06:50 UTC 2024


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](https://github.com/dlang/phobos/pull/8921) 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](https://youtu.be/3iWn4S8JV8g). 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](https://github.com/dlang/phobos/pull/8940). 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](https://issues.dlang.org/show_bug.cgi?id=22501).

Paul linked to [a Phobos 
v3](https://github.com/LightBender/PhobosV3-Design/discussions/20) discussion about taking predicates as runtime parameters. Steve noted there was a link there to [a forum post from Vladimir Panteleev](https://forum.dlang.org/post/qnigarkuxxnqwdernhzv@forum.dlang.org) 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.


More information about the Digitalmars-d-announce mailing list