Thread overview
Allocator Part of Type
Mar 15, 2018
jmh530
Mar 15, 2018
jmh530
Mar 16, 2018
Eugene Wissner
Mar 16, 2018
jmh530
March 15, 2018
I recall some talk Andrei did where he said it was a bad idea to make the allocator part of the type.  However, the container library in dlang-community(says it is backed with std.experimental.allocator) contains allocator as part of the type. Automem does too. Honestly, I would think you would really be hobbled if you didn't. For instance, if you want to expand a DynamicArray using the built-in ~= operator, then you really need to know what the allocator is. Without ~= you'd have to rely on functions (maybe member functions, maybe not).

So I suppose I'm wondering why is it a bad thing to include the allocator as part of the type and why is it that it seems like in practice that's how it is done anyway.
March 15, 2018
On 3/15/18 3:36 PM, jmh530 wrote:
> I recall some talk Andrei did where he said it was a bad idea to make the allocator part of the type.  However, the container library in dlang-community(says it is backed with std.experimental.allocator) contains allocator as part of the type. Automem does too. Honestly, I would think you would really be hobbled if you didn't. For instance, if you want to expand a DynamicArray using the built-in ~= operator, then you really need to know what the allocator is. Without ~= you'd have to rely on functions (maybe member functions, maybe not).
> 
> So I suppose I'm wondering why is it a bad thing to include the allocator as part of the type and why is it that it seems like in practice that's how it is done anyway.

I don't know if I've heard Andrei talk about that, but I definitely have made it part of the type for types that need to allocate. The only other possibility is to accept and use an Allocator object (i.e. the interface).

I suppose the main reason you may want to not make it part of the type is if you want to compare/assign two types built with different allocators. But then I don't know why you would want to do that.

But I just thought of this too -- maybe he said you should make it a part of the struct itself? That is, you shouldn't make the allocator a member, but the allocator itself can be part of the type?

Not sure.

-Steve
March 15, 2018
On Thursday, 15 March 2018 at 21:43:41 UTC, Steven Schveighoffer wrote:
> [snip]
> I don't know if I've heard Andrei talk about that, but I definitely have made it part of the type for types that need to allocate. The only other possibility is to accept and use an Allocator object (i.e. the interface).
>
> I suppose the main reason you may want to not make it part of the type is if you want to compare/assign two types built with different allocators. But then I don't know why you would want to do that.
>
> But I just thought of this too -- maybe he said you should make it a part of the struct itself? That is, you shouldn't make the allocator a member, but the allocator itself can be part of the type?
>
> Not sure.
>
> -Steve

I first remember him saying it with respect to C++'s allocators [1]. The C++ containers in std include the allocator as part of the type. I don't really recall what the reasoning was. I also recall him saying it with respect to automem [2].

Automem includes the allocator among the template variables and then puts the allocator in an enum (Atila says it only takes up space in certain situations). I think the containers library does something similar, but with an alias if state size is 0 and as a member otherwise.



[1] https://github.com/CppCon/CppCon2015/blob/master/Presentations/allocator%20Is%20to%20Allocation%20what%20vector%20Is%20to%20Vexation/allocator%20Is%20to%20Allocation%20what%20vector%20Is%20to%20Vexation%20-%20Andrei%20Alexandrescu%20-%20CppCon%202015.pdf

[2] https://forum.dlang.org/post/ocden9$11s6$1@digitalmars.com
March 15, 2018
On 3/15/18 6:30 PM, jmh530 wrote:
> On Thursday, 15 March 2018 at 21:43:41 UTC, Steven Schveighoffer wrote:
>> [snip]
>> I don't know if I've heard Andrei talk about that, but I definitely have made it part of the type for types that need to allocate. The only other possibility is to accept and use an Allocator object (i.e. the interface).
>>
>> I suppose the main reason you may want to not make it part of the type is if you want to compare/assign two types built with different allocators. But then I don't know why you would want to do that.
>>
>> But I just thought of this too -- maybe he said you should make it a part of the struct itself? That is, you shouldn't make the allocator a member, but the allocator itself can be part of the type?
>>
>> Not sure.
>>
> 
> I first remember him saying it with respect to C++'s allocators [1]. The C++ containers in std include the allocator as part of the type. I don't really recall what the reasoning was. I also recall him saying it with respect to automem [2].
> 
> Automem includes the allocator among the template variables and then puts the allocator in an enum (Atila says it only takes up space in certain situations). I think the containers library does something similar, but with an alias if state size is 0 and as a member otherwise.
> 
> 
> 
> [1] https://github.com/CppCon/CppCon2015/blob/master/Presentations/allocator%20Is%20to%20Allocation%20what%20vector%20Is%20to%20Vexation/allocator%20Is%20to%20Allocation%20what%20vector%20Is%20to%20Vexation%20-%20Andrei%20Alexandrescu%20-%20CppCon%202015.pdf 

Looks like what he means is that the allocator in C++ includes the type as part of it's makeup. That's not the same thing. But it's hard to tell from just a bunch of slides.

> [2] https://forum.dlang.org/post/ocden9$11s6$1@digitalmars.com

This does seem to suggest he thinks the idea is not good. I can't think of an alternative that doesn't store the allocator as a member (if you intend to use different allocators with different variables).

However, there is some further conversation on that from Martin Nowak that may shed some light on the "anti-pattern" and what it really means. Personally, I think you HAVE to have some sort of reference to an allocator if you want custom allocation support in a container type. The only other alternative is making the user of the type remember which allocator the type needs to dealloacte and pass the allocator along when doing memory management tasks. Seems horrible.

-Steve
March 16, 2018
On Thursday, 15 March 2018 at 19:36:10 UTC, jmh530 wrote:
> I recall some talk Andrei did where he said it was a bad idea to make the allocator part of the type.  However, the container library in dlang-community(says it is backed with std.experimental.allocator) contains allocator as part of the type. Automem does too. Honestly, I would think you would really be hobbled if you didn't. For instance, if you want to expand a DynamicArray using the built-in ~= operator, then you really need to know what the allocator is. Without ~= you'd have to rely on functions (maybe member functions, maybe not).
>
> So I suppose I'm wondering why is it a bad thing to include the allocator as part of the type and why is it that it seems like in practice that's how it is done anyway.

I think it is done in D, because it was always done in C++ this way, so it is known to be a working solution.

I see two reasons to make the allocators part of the type
1. Virtual function calls are slow, so let us do all allocators to structs and then we can pass them as a part of the type without using stuff like IAllocator, allocatorObject etc.
2. Used allocator is actually known at compile-time, so it can be decided at compile-time what allocator to use.

Now there are Bloomberg Labs allocators for C++ [1] (or BDE allocators), that are polymorphic allocators, so the allocators just implement an interface. The main reasoning behind it was as far as I remember to reduce compile time (and Bloomberg has tons of C++ code), so they developed these allocators and containers that accept the allocator as constructor argument and save it as a container member.

The main problem with allocators as part of the type isn't that you can't compare or assign types with different allocators - with a bit metaprogramming it is easy. The problem for me is that all you code should be templated then. You can't have a function

"void myFunc(Array!int)"

because it would work only with one allocator if the allocator is part of the type.

So I'm using polymorphic allocators for a long time [2].

I'm surprised to see that std.experimental.allocator documentation includes now an example how to save "the IAllocator Reference For Later Use".

[1] https://github.com/bloomberg/bde/wiki/BDE-Allocator-model
[2] https://github.com/caraus-ecms/tanya/blob/80a177179d271b6d023f51aa3abb69376415b36e/source/tanya/container/array.d#L205
March 16, 2018
On Friday, 16 March 2018 at 06:20:42 UTC, Eugene Wissner wrote:
>
> [snip]

That's interesting thanks.