Live data from Hacker News

C constructs that still don't work in C++

lospino.so

171–180 of 182 posts

Re: C constructs that still don't work in C++

#171

Earlier quoted context omitted.

> Because some warnings are just believed to be more serious, than others. Yes, that is my entire point. For some reason you were arguing against it.

I didn't intend to. > Also, let's not forget that implicit casts between unrelated pointer types is only a warning in C. I intended to argue against the "only a warning", because the meaning of a warning in C is something very serious. That is different from more modern languages, who may use this to inform you that you are no longer writing idiomatic code. Of course there are also exceptions, that you often need to…

But you can't argue that a warning is less severe than a hard compiler error. Warnings can be supressed or ignored.

You were right to call out that the C standard only talks about diagnostics and the actual implementation is left to the compilers, but I don't think it really changes the actual argument I've been trying to make, namely that - unlike in C++ - implicit incompatible pointer casts are not a guaranteed compiler error.

Re: C constructs that still don't work in C++

#172
post #164

Earlier quoted context omitted.

I don't see why it would easy to lose type information in circumstances where you can do monomorphization. Note that I do not assume "perfect deductive ability". The practical observation is simply that it is far more effort to deduplicate than to clone.

I am not sure why either (I believe it is aliasing), here's an example: https://godbolt.org/z/9szhxoxrf From the code, we can already tell all elements have the same type, but the compiler is already adding checks. One of the options would be to convert the array of fat pointers into a fat slice. But now you have to enlarge the slice's vtable with all possible item operations, even if we don't use them often. Alterna…

I see, this is what you meant. GCC can not currently do this. But this also not something that would correspond to a monomorphic version. A polymorphic function over a generic array would be specialized to one member type via monomorphization. This would correspond to this: https://godbolt.org/z/nd333xeTP

Re: C constructs that still don't work in C++

#173
post #172

Earlier quoted context omitted.

I am not sure why either (I believe it is aliasing), here's an example: https://godbolt.org/z/9szhxoxrf From the code, we can already tell all elements have the same type, but the compiler is already adding checks. One of the options would be to convert the array of fat pointers into a fat slice. But now you have to enlarge the slice's vtable with all possible item operations, even if we don't use them often. Alterna…

I see, this is what you meant. GCC can not currently do this. But this also not something that would correspond to a monomorphic version. A polymorphic function over a generic array would be specialized to one member type via monomorphization. This would correspond to this: https://godbolt.org/z/nd333xeTP

A bit of a nitpick, but I think this would be closer to a generic array: https://godbolt.org/z/cfdPWb6zz

Still, adding a different typed array already breaks inlining, https://godbolt.org/z/zavojE8xK (type-erasure) vs. https://godbolt.org/z/barroPfsP (monomorphized).

Aside from being heavily optimization-dependant, thinking through this, I've realized that type-erasure is a bit of a premature abstraction. It forces programmers to use indirection and pass-by-reference/pointer. It forces functions to be type size and alignment-agnostic. That's why type-erasure can't express monomorphism proper, whereas the reverse is not true.

Re: C constructs that still don't work in C++

#174
post #172

Earlier quoted context omitted.

I see, this is what you meant. GCC can not currently do this. But this also not something that would correspond to a monomorphic version. A polymorphic function over a generic array would be specialized to one member type via monomorphization. This would correspond to this: https://godbolt.org/z/nd333xeTP

A bit of a nitpick, but I think this would be closer to a generic array: https://godbolt.org/z/cfdPWb6zz Still, adding a different typed array already breaks inlining, https://godbolt.org/z/zavojE8xK (type-erasure) vs. https://godbolt.org/z/barroPfsP (monomorphized). Aside from being heavily optimization-dependant, thinking through this, I've realized that type-erasure is a bit of a premature abstraction. It forces p…

It is trivial to see that the compiler could do inlining also in this case. Your modification does not "break" inlining in the sense of making it impossible. In fact, just making the vtables "const" is enough and it does it: https://godbolt.org/z/oYv47xx8G Or adding "inline" would also do it. (But this not why your argument is wrong.)

The compiler chooses to not inline in your example. And this is the point: The compiler makes inlining decisions based on some heuristics exactly because inlining is not always an advantage (even if it is in toy examples), otherwise it would do it far more often. Implementing type-erasure gives it the freedom to do this while monomorphization hardcodes it. It takes away this freedom. You can get the same result as monomorphization by forcing certain inlining or function-cloning decisions, but the reverse is much harder: you can not automatically deduplicate the already expanded function. (in theory yes, in practice no)

The argument that for a language with type-erasure the inlining heuristics of this specific C compiler may not be ideal, is rather irrelevant. (but interprocedural value propagation is rather smart in principle)

Re: C constructs that still don't work in C++

#175

Earlier quoted context omitted.

I didn't intend to. > Also, let's not forget that implicit casts between unrelated pointer types is only a warning in C. I intended to argue against the "only a warning", because the meaning of a warning in C is something very serious. That is different from more modern languages, who may use this to inform you that you are no longer writing idiomatic code. Of course there are also exceptions, that you often need to…

But you can't argue that a warning is less severe than a hard compiler error. Warnings can be supressed or ignored. You were right to call out that the C standard only talks about diagnostics and the actual implementation is left to the compilers, but I don't think it really changes the actual argument I've been trying to make, namely that - unlike in C++ - implicit incompatible pointer casts are not a guaranteed com…

In don't think this is required in C++ either.

Re: C constructs that still don't work in C++

#176
post #174

Earlier quoted context omitted.

A bit of a nitpick, but I think this would be closer to a generic array: https://godbolt.org/z/cfdPWb6zz Still, adding a different typed array already breaks inlining, https://godbolt.org/z/zavojE8xK (type-erasure) vs. https://godbolt.org/z/barroPfsP (monomorphized). Aside from being heavily optimization-dependant, thinking through this, I've realized that type-erasure is a bit of a premature abstraction. It forces p…

It is trivial to see that the compiler could do inlining also in this case. Your modification does not "break" inlining in the sense of making it impossible. In fact, just making the vtables "const" is enough and it does it: https://godbolt.org/z/oYv47xx8G Or adding "inline" would also do it. (But this not why your argument is wrong.) The compiler chooses to not inline in your example. And this is the point: The comp…

My issue isn't that the modification made it impossible to inline, more so how trivial it was: I just added a different type. Generally, optimizations are disabled not because the compiler finds them inneficent, but because it lacks enough contextual information/intelligence to safely add it. So similar to what you said, in theory, the compiler can optimize type-erasure just like monomorphism, but, in practice, it lacks info to do so. Either by programmer accident, language/compiler limitations, or both.

Also, monomorphization doesn't actually take the compiler freedom away (on its own) to optimize. Similar to how type-erasure can be optimized to behave like monomorphization through devirtualization, monomorphized calls can be virtualized (which Swift shows). The problem is that it takes away transparency from the programmer. It also changes the semantics of the call behind the scene (type-erasure is strictly pass-by-pointers, monomorphism is not). That wouldn't work well for a low-level language.

Re: C constructs that still don't work in C++

#177
post #174

Earlier quoted context omitted.

It is trivial to see that the compiler could do inlining also in this case. Your modification does not "break" inlining in the sense of making it impossible. In fact, just making the vtables "const" is enough and it does it: https://godbolt.org/z/oYv47xx8G Or adding "inline" would also do it. (But this not why your argument is wrong.) The compiler chooses to not inline in your example. And this is the point: The comp…

My issue isn't that the modification made it impossible to inline, more so how trivial it was: I just added a different type. Generally, optimizations are disabled not because the compiler finds them inneficent, but because it lacks enough contextual information/intelligence to safely add it. So similar to what you said, in theory, the compiler can optimize type-erasure just like monomorphism, but, in practice, it la…

But your example did not show that the compiler lacks the contextual information. My argument is exactly that in all cases where one can do monomorphization, this contextual information is trivially available because it simply a small part of what can be done with interprocedural constant-propagation anyhow. I think this is easy to see.

I am not commenting on your Gish Gallop of new arguments.

Re: C constructs that still don't work in C++

#178
post #177

Earlier quoted context omitted.

My issue isn't that the modification made it impossible to inline, more so how trivial it was: I just added a different type. Generally, optimizations are disabled not because the compiler finds them inneficent, but because it lacks enough contextual information/intelligence to safely add it. So similar to what you said, in theory, the compiler can optimize type-erasure just like monomorphism, but, in practice, it la…

But your example did not show that the compiler lacks the contextual information. My argument is exactly that in all cases where one can do monomorphization, this contextual information is trivially available because it simply a small part of what can be done with interprocedural constant-propagation anyhow. I think this is easy to see. I am not commenting on your Gish Gallop of new arguments.

How did it not lack of contextual info? By adding "const", you provided more info to the compiler, and it decided it was safe to inline, despite no actual behavior change. My point is, despite the possibility, these optimizations are easy to disable by mistake.

Also, there's no gish-gallop. You said the compiler can optimize type-erasure like monomorphization, but not monomorphization like type-erasure, and I said that's not true: the compiler can, in fact, do that. I simply addressed your argument. The rest simply elaborates on why languages why might not do it.

Re: C constructs that still don't work in C++

#179
post #177

Earlier quoted context omitted.

But your example did not show that the compiler lacks the contextual information. My argument is exactly that in all cases where one can do monomorphization, this contextual information is trivially available because it simply a small part of what can be done with interprocedural constant-propagation anyhow. I think this is easy to see. I am not commenting on your Gish Gallop of new arguments.

How did it not lack of contextual info? By adding "const", you provided more info to the compiler, and it decided it was safe to inline, despite no actual behavior change. My point is, despite the possibility, these optimizations are easy to disable by mistake. Also, there's no gish-gallop. You said the compiler can optimize type-erasure like monomorphization, but not monomorphization like type-erasure, and I said th…

No, you did not address my argument. You need to show that it is impossible (or hard) to do function cloning when using interprocedural constant-propagation in a situation where monomorphism does this. But nothing you said contradicts this and the fact that a C compiler may sometimes decide to inline or not a function is completely irrelevant to this question.

In fact, it was exactly my argument that it is an advantage of type-erasure that the compiler has more freedom. An example where the compiler does not specialize a function just demonstrates this flexibility.

Re: C constructs that still don't work in C++

#180
post #179

Earlier quoted context omitted.

How did it not lack of contextual info? By adding "const", you provided more info to the compiler, and it decided it was safe to inline, despite no actual behavior change. My point is, despite the possibility, these optimizations are easy to disable by mistake. Also, there's no gish-gallop. You said the compiler can optimize type-erasure like monomorphization, but not monomorphization like type-erasure, and I said th…

No, you did not address my argument. You need to show that it is impossible (or hard) to do function cloning when using interprocedural constant-propagation in a situation where monomorphism does this. But nothing you said contradicts this and the fact that a C compiler may sometimes decide to inline or not a function is completely irrelevant to this question. In fact, it was exactly my argument that it is an advanta…

I feel like you are attacking a strawman here. My point isn't that it's impossible to optimize, but such optimizations are fickle and easy to break by programmer error and require adequate language expressivity (although low-level languages generally provide that).

You say that the compiler made the decision to not inline it because it judged it to be the most efficient, yet, by adding the "const", thus adding more info, it did inline it. Why did the heuristics change here, even though the logic remained the same? I argue it's not because the compiler decided it would be more performant to not inline, but that it was acting on the side of caution.

Finally, if giving the compiler more freedom to make choices is your goal, then forcing it to start by either type-erasure or monomorphization is the wrong answer. The compiler should be free to choose type-erasure/monomorphization from the start in such case. However, that introduces limitations to the language. Since the generic function is prohibited from knowing the type size at compile time, it can't allocate space for it in the stack. Long story short, I think you'd be forcing the programmer into an abstraction they might not need nor would necessarily help them, and then hoping the compiler to optimize appropriately.

Personally, I care about expressivity and transparency, thus I think having both natively supported is preferable. But if one must be chosen over the other, monomorphism should come first, as you can build a vtable with it (also, there are many ways to build vtables and dynamically diapatch).

Post reply on HN