Live data from Hacker News

The first new build of Circle, a new C++20 compiler, since April 2022 is online

github.com

71–80 of 80 posts

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#71

Earlier quoted context omitted.

> if you have a bunch of functions that do fundamentally the same thing with different types That's where you should use parametric polymorphism, that's my point. C++ 23 defines _3_ overloads of string.contains() with parameter defined as variously a char, a char * and a string view, enabling name.contains("Jim") name.contains("Steve"sv) and name.contains('Q'). But if you need a fourth, too bad. Rust doesn't have ove…

Just to be precise, traits and overloading are a form ad-hoc polymorphism not parametric.

Hmm, imagine I invent a new string matching predicate doop() which I want to define. My doop predicate says that the thing we're matching should occur both at the beginning, and the end, and these occurrences should not overlap. That is, there should exist some partition of our string such as that string.doop(pattern) implies all of: s1 + s2 = string and s1.starts_with(pattern) and s2.ends_with(pattern)

In C++ I need to overload doop() exactly three times, once for each of the three types we identified. I can't do it any other way, that's how it must be defined.

But in Rust I just write it once, in terms of Pattern, I don't need to understand how Pattern is actually implemented, that's opaque to me, I just use this Pattern trait and it all works.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#72

Earlier quoted context omitted.

Just to be precise, traits and overloading are a form ad-hoc polymorphism not parametric.

Hmm, imagine I invent a new string matching predicate doop() which I want to define. My doop predicate says that the thing we're matching should occur both at the beginning, and the end, and these occurrences should not overlap. That is, there should exist some partition of our string such as that string.doop(pattern) implies all of: s1 + s2 = string and s1.starts_with(pattern) and s2.ends_with(pattern) In C++ I need…

In C++ you would write it once, in term of some concept or other. In practice you would implement exactly the same number of functions you would in rust.

edit: to elaborate: some functionality can be implemented generically (i.e. parametrically ) in term of some other concepts, recursively. At some point the concepts need to map to actual concrete implementation, then you use ad hoc polymorphism. This is the same in rust and in c++ [1].

Additionally in C++, even when you can implement some functionality parametrically, it is sometime useful to (partially) specialize functions and types to take advantage of some optimizations (for example it is possible to implement std::copy generically, but it is often specialized for contiguous iterators to trivially copyable types to call memcpy).

[1] Rust does of course have a more principled handling of these concepts, which are often underdefined in c++.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#73
post #60

Earlier quoted context omitted.

I'd like to target Windows. Windows does impose a specific C++ ABI, but it's completely undocumented. It's really just whatever Visual C++ does. C++ ABI is very complex, especially vtable layout and RTTI and EH. I am looking to get Microsoft's assistance on targeting Windows. It's a priority, but they don't want to help yet.

Isn't that what com is for? Win32 is compiler agnostic.

https://itanium-cxx-abi.github.io/cxx-abi/abi.html See all the stuff there? exceptions, vtable layout, rtti, mangling, etc. There's a Windows equivalent for all of that. That's what I want access to.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#74

Earlier quoted context omitted.

Hmm, imagine I invent a new string matching predicate doop() which I want to define. My doop predicate says that the thing we're matching should occur both at the beginning, and the end, and these occurrences should not overlap. That is, there should exist some partition of our string such as that string.doop(pattern) implies all of: s1 + s2 = string and s1.starts_with(pattern) and s2.ends_with(pattern) In C++ I need…

In C++ you would write it once, in term of some concept or other. In practice you would implement exactly the same number of functions you would in rust. edit: to elaborate: some functionality can be implemented generically (i.e. parametrically ) in term of some other concepts, recursively. At some point the concepts need to map to actual concrete implementation, then you use ad hoc polymorphism. This is the same in…

I see. So, for example, Microsoft's STL is doing this wrong in stl/inc/xstring where it has, as I described, exactly three overloads of each such predicate with a separate implementation for each of the three types.

Do you have an example I can look at where it's done the way you imagine it "should" be done in C++?

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#75

Earlier quoted context omitted.

In C++ you would write it once, in term of some concept or other. In practice you would implement exactly the same number of functions you would in rust. edit: to elaborate: some functionality can be implemented generically (i.e. parametrically ) in term of some other concepts, recursively. At some point the concepts need to map to actual concrete implementation, then you use ad hoc polymorphism. This is the same in…

I see. So, for example, Microsoft's STL is doing this wrong in stl/inc/xstring where it has, as I described, exactly three overloads of each such predicate with a separate implementation for each of the three types. Do you have an example I can look at where it's done the way you imagine it "should" be done in C++?

Proof by implementation: https://godbolt.org/z/WYjPjsTWY

The reason the standard specifies the three overloads of course is because chars and chars literals that have been inherited from C are funny and those begin/end pairs are dangerous. But that's a quirk of C++ string types and nothing to do with parametric and ad-hoc polymorphism in C++.

edit: also the three overloads in MSVC probably forward to the same implementation over string_view (except possibly for char of course that can be implemented more efficiently).

edit2: I use concepts in my implementation just because. It would work just fine without them.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#76

Earlier quoted context omitted.

I see. So, for example, Microsoft's STL is doing this wrong in stl/inc/xstring where it has, as I described, exactly three overloads of each such predicate with a separate implementation for each of the three types. Do you have an example I can look at where it's done the way you imagine it "should" be done in C++?

Proof by implementation: https://godbolt.org/z/WYjPjsTWY The reason the standard specifies the three overloads of course is because chars and chars literals that have been inherited from C are funny and those begin/end pairs are dangerous. But that's a quirk of C++ string types and nothing to do with parametric and ad-hoc polymorphism in C++. edit: also the three overloads in MSVC probably forward to the same impleme…

Whilst that's clever I don't think it's actually practical at all.

I believe that your hypothetical approach, ignoring the fact it's not practical, is parametric polymorphism. We can invent more types of "needle" and use the same "needle" concept for other predicates, thus if we have N needles and M predicates that's N+M work, not N*M work as with the overloads.

However, what is actually practical, and thus what is done, is just ad hoc polymorphism via the overloading we looked at, if WG21 wants to expand it that's N*M implementation cost.

I do not believe we can claim something is ad hoc polymorphism solely because somewhere there's different implementation code for type A and type B as with your Godbolt example, if you believe that's ad hoc polymorphism surely you end up thinking std::sort is also ad hoc polymorphism which seems like nonsense.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#77

Earlier quoted context omitted.

Proof by implementation: https://godbolt.org/z/WYjPjsTWY The reason the standard specifies the three overloads of course is because chars and chars literals that have been inherited from C are funny and those begin/end pairs are dangerous. But that's a quirk of C++ string types and nothing to do with parametric and ad-hoc polymorphism in C++. edit: also the three overloads in MSVC probably forward to the same impleme…

Whilst that's clever I don't think it's actually practical at all. I believe that your hypothetical approach, ignoring the fact it's not practical, is parametric polymorphism. We can invent more types of "needle" and use the same "needle" concept for other predicates, thus if we have N needles and M predicates that's N+M work, not N*M work as with the overloads. However, what is actually practical, and thus what is d…

The begin/end overloads are ad-hoc polymorphism. The contains function is parametrically polymorphic.

My "hypothetical" approach is bog-standard generic programming in c++ has it has been practiced for almost 30 years since Stepanov originally codified it.

ADL was litterally designed to make this sort of stuff work.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#78

Truly an amazing project. One person implementing the entire C++ standard, and then countless new, useful features on top of it. Circle did the interpreted, compile-time pass idea before any of the other new systems languages. Carbon and C++Next both seem very directly "inspired" by Circle, but neither of those efforts seem to have actually produced anything yet. Ideally, Circle it would be open source. But I underst…

> Circle did the interpreted, compile-time pass idea before any of the other new systems languages. constexpr is in C++11, Jai is from 2014, and Zig 0.1.1 is from 2017. This project looks quite cool though.

D has had compile time function execution since 2007 or so.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#79

Earlier quoted context omitted.

Whilst that's clever I don't think it's actually practical at all. I believe that your hypothetical approach, ignoring the fact it's not practical, is parametric polymorphism. We can invent more types of "needle" and use the same "needle" concept for other predicates, thus if we have N needles and M predicates that's N+M work, not N*M work as with the overloads. However, what is actually practical, and thus what is d…

The begin/end overloads are ad-hoc polymorphism. The contains function is parametrically polymorphic. My "hypothetical" approach is bog-standard generic programming in c++ has it has been practiced for almost 30 years since Stepanov originally codified it. ADL was litterally designed to make this sort of stuff work.

It's hypothetical because you yourself admit the standard library implementations don't actually do this here. The real C++ string contains() does in fact only work for the three specific types implemented, and is not generic, and that's not merely an oversight it's how it necessarily works even though it's worse. Circle's Interfaces would offer a much nicer approach, which makes sense because they do the same thing as Rust's traits for this scenario.

You're right that in some places C++ does the generic thing, I pointed at std::sort already - there are lots of examples of varying quality. The way we got here is that I pointed out overloads are the Wrong Thing™ and that's why it makes sense Carbon would want to outlaw them, and why no, outlawing them does not lose the nice property where the API feels generic - you can do parametric polymorphism and still have the generic API.

The main thing outlawing overloading gets rid of is actually functions/ methods which quietly have more than one distinct purpose. These functions are foot guns. Use your words, call the two (or more) things by different names reflecting the difference in intent and then fewer developers will mistakenly invoke the wrong meaning.

I don't like ADL either, but it's pretty far off topic.

Re: The first new build of Circle, a new C++20 compiler, since April 2022 is online

#80
post #73

Earlier quoted context omitted.

Isn't that what com is for? Win32 is compiler agnostic.

https://itanium-cxx-abi.github.io/cxx-abi/abi.html See all the stuff there? exceptions, vtable layout, rtti, mangling, etc. There's a Windows equivalent for all of that. That's what I want access to.

Right I know what a C++ ABI is but I still don't get it. To write C++ apps on Linux you need to match the ABI because there are lots of raw libraries that are just straight compiled C++. On Windows it's not like that outside of the VC++ runtime itself. Everything is C APIs or COM, and wrappers around that. MS never documented their C++ ABI because as far as they're concerned it's not something anyone needs to know, in order to write Windows apps or have components/libraries interop with each other. They never expose raw C++ objects in Windows. When they have C++ APIs they come as source or headers.
Post reply on HN