C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Fwd: Extension to runtime polymorphism proposed

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Wed, 8 Apr 2026 02:38:28 +0200
śr., 8 kwi 2026 o 02:06 Muneem via Std-Proposals
<std-proposals_at_[hidden]> napisał(a):
>
> Summary of my points (to keep it simple for those who didn't understand):
>
> ***Type Safety is the priority***:
> With std::variant, you can assign a float to an object that should only be an int. That’s not type-safe. My type_set(selector) fixes this—once the runtime index picks the type, it’s fixed. You can't just swap it later.
>

No, this is not type safety. Please do not change the meaning of
words. Beside assigning float to int is a well defined operation.

>
> ****Compiler Freedom = Speed***:
> I’m calling for an implementation-defined container. This lets the compiler decide the best way to move or copy data (registers, stack, etc.) based on the ABI. It’s faster because the compiler isn’t fighting a rigid library structure. The compiler has the same freedom on when it instantiates type_set(selector) into T^. Tuples aren't implementation defined, since they have to provide some gurrenties and modifying tuples to fix this breaks the zero cost abstraction principle.
>

Funny that you mention ABI as is in many cases outside of compiler
control and once set can't be never changed.
And how tuple break the zero abstraction principle? If you make such
outlandish claims you need to prove it, and you did not do it
anywhere.

> ***Hybrid approach:*** I want compile-time known types with runtime indexing. std::tuple is too stiff for runtime, and std::variant is too loose. My proposal uses the existing branching/template mechanisms the compiler already has, just more efficiently. A mix of both of them is still bad since return variants would still lead to type unsafe code by being able to assign a float to int, as described in point 1.
>
>
> On Wed, 8 Apr 2026, 4:59 am Muneem, <itfllow123_at_[hidden]> wrote:
>>
>>
>> Before my response to Mr.sebistian and Mr. Simon:
>> Small correction in my last emai(the change is in point 3):
>> 1. The compiler can use a union, which case you have that advantage of the feature "potential merging multiple branches" that I talked about in my previous email.
>> 2. The compiler can cause a function call after each definition
>> 3.The compiler can do one of those, the second the variable is used or when the element has changed, the compiler can also choose the best point for instantion in between the varianle.defintion and when one of the two things happen.
>> 4.will never do one of those if the list is filled only with const qualified types ( don't know if it's a good idea yet because of user defined types.
>> 5.Again, in usage it will decay into T^, which can turn into at T& or T&&, so you can copy or move from it.
>>
>>
>> ****Small recap*****:
>> Basically the issue with tuples and this:
>> (The mr mr.sebistian thinks it should work for heterogeneous lists):
>> class Dispatch
>> {
>> public:
>> Dispatch(tuple<A, B, C> t, int index);
>> void op1();
>> void op2();
>> tuple<A, B, C>& _tupleref;
>> int _index;
>> };
>> tuple<A, B, C> t = { a, b, c }; // initialize
>> Dispatch<A, B, C> d(t, i); // select index i
>> i.op2(); // call operations
>> ***Issues***
>> 1.How do you get a tuple elements out, how do you get a tuple elements std::plus any type out. One way is to use variants, but then the variant returned can be assigned any type, which is again type safe. If I get an object of type A from the tuple or after adding the element at index 0 with another B, then I should not be able to assign B to it. That's not how type safe c++ is supposed to be.
>> The same issue exists for a array of variants
>> 2.It takes a type T^, why is that an issue?
>> Well, I may not be comfortable adding certain types in a list, for example for a bunch of representing a http packet, I may not be willing to have cookies in this list. The same applies to many users of heterogenous lists. Normal tuples won't allow me to put them in tuples and expect a special "safe" overload be called for them. In my proposals case, the overload will be that if T^; it fixes the downsides of the flexibility that heterogeneous lists provide.
>>
>>
>> Response to Mr.Sebistian:
>> >Just quickly answering 1)
>>
>> >Would you rather have the whole tuple copied everytime?
>>
>> >To the target stack frame?
>> >In your proposed solution you can also copy a pointer to the role or the whole tuple (as long as the optimizer does not optimize over the function call).
>> ****Answer****
>> 1.No, it would leave it to the compiler, by having a implementation defined container for this reason. Sometimes copying a tuple is efficient sometimes not. Many times however you would want to move the tuple, and return it back.
>> 2.In my proposal, since the container is implementation defined hence the compiler has a free hand in copying it however it wants and moving it however it wants.
>> 3. I don't know what you mean by copying a role , but I think you meant pointing to an element using a point and copying that point.if yes:
>> Then no you can't do that, you can't have pointers to type_set(selector) but can have points to T^, just like you can point to any other glvalue(T^) is a glvalue.
>>
>>
>>
>>
>>
>> >It will be faster only for small tuples, which perhaps can be passed in registers.
>> >But it is a simple change for Dispatch to store the tile instead of a pointer to the tuple.
>> >If you want to use the select to make the tuple smaller for directly copying the tuple, then just store the selected element as a variant in the Dispatch object.
>> ****ANSWER****
>> 1. No, my solution would be faster for heterogeneous list of any type because the compiler has full say in weather to copy it or not, and how to copy it, since the container is implementation defined.
>> 2. What's a tile into the tuple? Please elaborate the thing that you mean by tile.
>> 3. Variants don't have fixed types, hence for heterogeneous lists, they aren't an option at all. Even if say a A.dispatch(runtime index,std::plus, float{1}) return a variant that can have int, float, and I assign that variant to an object X of the same variant type, then object X can hold both float, int, but In heterogenous lists, I don't want that, I want the type to be fixed. So a tuple of built in types that have fixed types at each index is impossible, without the new value type type_set(selector).
>> Where as in my solution, object: type_set(selector) X= selector(runtime_index)
>> Can only hold what runtime_index was fixed to hold. So my proposal makes code more type safe and easy for reason about.
>>
>>
>> >With your proposal the compiler has to break down your constructs, too. It also has to pass something to functions (if ABI boundary and not optimized over function calls). If you can program the same with current C++ we can reason about it.
>> >I try to distill, what is actually new in your proposal.
>> >That it also cannot be provided by one layer of C++, which would lead to the same assembly anyway, if it is equivalent to your proposed language extension.
>> >Perhaps we find one small new language feature and another thing which can be expressed with some syntactic sugar.
>> >A language feature can be interface like ad-hoc relationships between types with common member function signatures.
>> >Otherwise perhaps 1 or 2 hints for the optimizer
>> ****ANSWER****
>> 1.thats why I proposed new value types, so that the compiler can use the existing branching and template instantion mechanisms. The compiler won't have to do anything other than use the existing mechanisms more efficiently to index the heterogeneous list. It basically uses the existing features compilers have. Like it does not have to break down constructs, just implementation defined container to get the type_set(selector), and instnatiate it into every possible T^. Like again, we have a million branching techniques the compilers already have.
>> 2. It's not just 2 or 3 optimizations:
>> 1. It's better type safety :
>> Type_set(selector) X= selector(runtime index)
>> The element at runtime index was int then you CANT assign float to X. This is an issue that std::variants fails to address. You may want to modify std::variant but that would either need changing how unions work or produce new expression type that my proposal already does.
>> 2. Extended metaprogramming capabilities by simply merging current branching and template mechanisms.
>> 3. This can be provided by one layer of c++ because c++ already has templates and branching facilities.
>>
>>
>>
>>
>> You want to move code generation to the location of the final op call, you don't want to use pointers, but want to send only the needed information through function call or even ABI boundaries.
>> ****ANSWER****
>> 1. I want code generation when ever type_set(selector) is used, and the compiler can merge the branches generated if it wants. I don't want to use pointers because again, they don't provide copy/move without having to allocate a new object all together or have the risk of slicing.
>> 2. It's up to the compiler on what information to send for each branch.
>>
>>
>> My response to Mr.Simon:
>> JSON and XML where the examples I have provided before. However, these only work if we have a runtime heterogeneous list. Until now (especially with your example from the Turing virtual machine) we were talking about heterogeneous lists known at compile time. The solutions to these problems differ a lot: at compile time we can just use std::tuple. However, if we want to modify a list at runtime we are back to std::vector<std::variant> (or something similar). With your most recent explanations we are closer to the latter. However, the most efficient solution in your case would work with a std::tuple rather than with a std::vector<std::variant>. If the types are fixed at compile time the compiler can optimize much better.
>>
>> So, which one do you want? Compile time lists or runtime lists? (Runtime indices would be allowed in both cases.)
>> ****ANSWER****
>> I want a compile time known implementation defined container of type type_set(selector for the reasons described in the "Small recap" recap section.
>>
>>
>> On Tue, 7 Apr 2026, 5:01 pm Simon Schröder via Std-Proposals, <std-proposals_at_[hidden]> wrote:
>>>
>>>
>>>
>>> On Tue, Apr 7, 2026 at 10:58 AM Muneem via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>>>
>>>> You may disagree for the need of T^ but again considering that heterogeneous lists will mostly be ever used in networking protocols, JSONs, XMLs, you want as the programmer to have a freehand in providing (application) safety, when you let a user index your list with any index he wants.
>>>
>>>
>>> JSON and XML where the examples I have provided before. However, these only work if we have a runtime heterogeneous list. Until now (especially with your example from the Turing virtual machine) we were talking about heterogeneous lists known at compile time. The solutions to these problems differ a lot: at compile time we can just use std::tuple. However, if we want to modify a list at runtime we are back to std::vector<std::variant> (or something similar). With your most recent explanations we are closer to the latter. However, the most efficient solution in your case would work with a std::tuple rather than with a std::vector<std::variant>. If the types are fixed at compile time the compiler can optimize much better.
>>>
>>> So, which one do you want? Compile time lists or runtime lists? (Runtime indices would be allowed in both cases.)
>>> --
>>> Std-Proposals mailing list
>>> Std-Proposals_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2026-04-08 00:38:48