September 01, 2021

On Wednesday, 1 September 2021 at 10:32:41 UTC, Per Nordlöw wrote:

>

On Tuesday, 31 August 2021 at 17:21:02 UTC, deadalnix wrote:

>

I want to start working on a container library. Interestingly enough, I don't think we have what we need on that front.

You give Razvan and Andrei a ping aswell. They have done deep work on the topic of specifically trying to make RC-backed containers/collections @safe pure nothrow @nogc. One of Andrei's conclusion was that a run-time flag is needed to reveal whether a const parameter is fed an immutable argument or not.

I started looking into this after a short discussion with Andrei :)

September 01, 2021

On Wednesday, 1 September 2021 at 10:32:45 UTC, deadalnix wrote:

> >
  • Will you be supporting

Ignore that. An editing mistake.

>

I'm not sure what you mean here. If it is bugfixes and all, I don't have much problem with that. Container are fairly straightforward, so I don't expect the workload to be very high anyways.

September 01, 2021

On Tuesday, 31 August 2021 at 17:21:02 UTC, deadalnix wrote:

>

I want to start working on a container library. Interestingly enough, I don't think we have what we need on that front.

Moreover, Rust collections provides makes rich of static members such as [1]

C.with_capacity(size_t)

instead of guessing what C(42) means which have introduced bugs in my code previously.

Might be worthwhile considering making use of these patterns.

My containers make use of such static members.

[1] https://doc.rust-lang.org/std/vec/struct.Vec.html#method.with_capacity.

September 01, 2021

On 8/31/21 8:26 PM, Paul Backus wrote:

>

On Tuesday, 31 August 2021 at 23:56:51 UTC, Steven Schveighoffer wrote:

> >

To put it bluntly, I have no idea how to achieve this. And I don't think we'll have a good set of collection before this is sorted out.

I had an idea a long time ago, but ashamedly never brought it to fruition. But long story short, I think we need a way to specify "tail" for modifiers, and allow implicitly casting the head. Then you'd have tailconst(Vector!int), and you are good. I actually had a decent syntax for it, but I'm not sure it would fly anyway.

One problem I can forsee with this approach is that, from the compiler's point of view, there is not necessarily any predictable relationship between qualifier(Template!T) and Template!(qualifier(T)).

It's possible to forward, i.e.:

template Vector(T) if (isConst!T) { alias Vector = tailconst(.Vector!(Unqual!T)); }

If you look at arrays, const(T)[] is the same as tailconst(T[]). This would be similar.

The problem I have with any other approach is that the compiler doesn't understand the relationships, and you will run into weird corner cases. It can't correctly add or strip the qualifier to the correct members when calling compatible functions.

-Steve

September 01, 2021

On 8/31/21 8:52 PM, deadalnix wrote:

>

On Tuesday, 31 August 2021 at 23:56:51 UTC, Steven Schveighoffer wrote:

>

I don't agree that COW is a good idea for generic collections. IIRC, C++ tried this with std::string and it was a disaster.

You seem to be confused. The C++11 standard prohibits std::string from using COW. Existing C++ implementations were using COW, and getting out of it was what was a disaster (notably, there were breaking ABI changes, which the C++ ecosystem is not well suited to handle).

Isn't the reason they prohibited COW is because of the problems with it?

Not saying COW is terrible in all cases, just that a generic container (non-specialized usage) should not be COW. If you need that feature, you should have to ask for it, not have it be an implementation detail.

-Steve

September 01, 2021

On Wednesday, 1 September 2021 at 10:44:46 UTC, Per Nordlöw wrote:

>

On Tuesday, 31 August 2021 at 17:21:02 UTC, deadalnix wrote:

>

I want to start working on a container library. Interestingly enough, I don't think we have what we need on that front.

Moreover, Rust collections provides makes rich of static members such as [1]

C.with_capacity(size_t)

instead of guessing what C(42) means which have introduced bugs in my code previously.

Might be worthwhile considering making use of these patterns.

My containers make use of such static members.

[1] https://doc.rust-lang.org/std/vec/struct.Vec.html#method.with_capacity.

I have adopted that style a lot lately and this is indeed much better than C(42).

September 01, 2021

On Wednesday, 1 September 2021 at 11:13:27 UTC, Steven Schveighoffer wrote:

>

Isn't the reason they prohibited COW is because of the problems with it?

Not saying COW is terrible in all cases, just that a generic container (non-specialized usage) should not be COW. If you need that feature, you should have to ask for it, not have it be an implementation detail.

-Steve

Well I never experienced any problem with them, so did many other C++ users. As far as i am concerned, this was a net step backward.

That being said, the reason were due to iterator invalidation. There are several function in the string API that do not invalidate iterators, as per the C++ standard, and these function might end up copying the content of the string in some specific situations, which would invalidate iterators.

In practice, I think the main problem here is related to exposing the innards of the datastructure. An iterator that contains a reference to the container + index, rather than some kind of raw pointer for instance, could avoid that problem.

September 01, 2021

On Wednesday, 1 September 2021 at 11:04:41 UTC, Steven Schveighoffer wrote:

>

It's possible to forward, i.e.:

template Vector(T) if (isConst!T) { alias Vector = tailconst(.Vector!(Unqual!T)); }

If you look at arrays, const(T)[] is the same as tailconst(T[]). This would be similar.

This runs directly into the issue 1807 problem. The compiler has to recognize this specific pattern as meaningful, and if the programmer writes something semantically equivalent using a different pattern, their code will mysteriously break; e.g.,

alias TailConstOf(T) = tailconst(T);
alias Vector(T : const(U)) = TailConstOf!(.Vector!U);
>

The problem I have with any other approach is that the compiler doesn't understand the relationships, and you will run into weird corner cases. It can't correctly add or strip the qualifier to the correct members when calling compatible functions.

With the implicit opCast/constructor approach (or the opHeadMutable approach), the compiler doesn't have to understand the relationships. It just needs to know the original type and the desired type, and call the appropriate user-defined function to perform the conversion.

September 02, 2021
On 01/09/2021 10:32 PM, deadalnix wrote:
>> - An interesting emsi container that was new to me is `UnrolledList`. It's used extensively in dsymbol.
>>
> 
> I have no idea what that is.

Unrolled linked list, a linked list with X number of entries per node.

Very good for cache efficiency especially if you need append only.
September 01, 2021

On 9/1/21 7:57 AM, Paul Backus wrote:

>

On Wednesday, 1 September 2021 at 11:04:41 UTC, Steven Schveighoffer wrote:

>

It's possible to forward, i.e.:

template Vector(T) if (isConst!T) { alias Vector = tailconst(.Vector!(Unqual!T)); }

If you look at arrays, const(T)[] is the same as tailconst(T[]). This would be similar.

This runs directly into the issue 1807 problem. The compiler has to recognize this specific pattern as meaningful, and if the programmer writes something semantically equivalent using a different pattern, their code will mysteriously break; e.g.,

alias TailConstOf(T) = tailconst(T);
alias Vector(T : const(U)) = TailConstOf!(.Vector!U);

Right, we have to fix that problem anyway.

To further explain for readers, the issue is:

void foo(T)(Vector!(const(T)) arg);

This should accept a Vector!(const int) which is aliased as tailconst(Vector!int), but the compiler can't see how to infer T as int from tailconst(Vector!int). I think the implicit cast solution suffers from similar problems. It works fine if you use const(T)[], which is the standard we should strive for.

This is one of those longstanding issues that needs addressing.

>

With the implicit opCast/constructor approach (or the opHeadMutable approach), the compiler doesn't have to understand the relationships. It just needs to know the original type and the desired type, and call the appropriate user-defined function to perform the conversion.

It just means you need to handle all the implicit conversions, which is not trivial. The compiler already has rules for implicit const conversions, some of which have subtle pitfalls if you get them wrong. I'd rather utilize those mechanisms rather than relying on each type author to get them all right.

-Steve