On Wednesday, 22 October 2025 at 14:40:58 UTC, H. S. Teoh wrote:
> On Wed, Oct 22, 2025 at 09:10:03AM +0000, monkyyy via Digitalmars-d-learn wrote:
> https://youtu.be/1p6So6vE5WM?si=tEbeBOQ-xXjJawMY
"if its a subset it automagically picks the right one because of our clever overload rules"
No, No, just No; every overload set with >5 memebers is a big ball of bugs such as to
These are type assertions; isComaparable!(T,U)=>bool could be made
with a reusable error code by as template assertComaparable(T,U,string func=__FUNCTION__) =>
"max of int and string requires opCmp, consider:
- .to!string of the first argument
- .to!int of th 2nd argument
- implementing int.opCmp(string)
- implementing string.opCmp(int)
"
I've argued this before: many instances of overload sets in Phobos should not be overload sets at all, but should be single functions (or perhaps a much smaller overload set) with static if's inside the function body to dispatch to the various implementations, along with static assert's that provide helpful error messages for when the arguments don't match any of the static if conditions.
The user-facing function signature should describe the logical API, rather than implementation details such as "if input is a float, if input is an enum, ..." ad nauseaum. Logically, std.conv.to is supposed to accept all types (even if the current implementation may or may not accept everything), so the function signature should be:
T to(T,U)(U data) { ... }
without any signature constraints. All the stuff like "if U is floating-point, if U is enum, if U is struct, ...", etc., are implementation details, that should be left to static if's inside the function body rather than clutter the API with an incomprehensibly large overload set.
T
This thread is probably more appropriate for the General forum than this one.
Anyway, I haven't watched the Youtube video, but I'm not quite as negative on C++ concepts as others.
I think you put this well, but I'm not so sure it is necessarily a negative with respect to concepts, or otherwise putting template constraints in the signature, provided there is a single function. For instance, it makes sense for to to work with any type, but maybe it makes sense to constrain a function that should only work on floating point types to say that in the signature (and then if integer types are added later, then it can put a numeric type in the signature and have the interger/floating point handling happen inside the function as an implementation detail).
I think it's a question of best practices and making sure they are widely understood.
The lingering issue is how to manage the organization of the code and corresponding template bloat. If people follow your advice and then have the toImpl helper functions within static if blocks to improve organization, then that might increase template bloat compared to having separate functions.
In one thing I was working on (that got really annoying to finish off and my time got limited so I haven't had a chance to finish it off), I was dealing with types that (basically) could be any kind of floating point type, with different allocation strategies, and (more-or-less) different ways to iterate through them. And then passing this off to functions that only vary based on floating point type. So you had to take the original types, convert them slightly, and then pass them off to the downstream function. But then you throw const/immutable into dealing with it, which added another set of complexity. I think what I ended up doing was a separate function signature depending on the allocation type. But then since each function could take two inputs, it ended up with like 6. And then those all ended up calling down to one function.
Long story short, it was a real headache.
If it were possible to just have a one line function signature with all the implementation complexity in the static if's, while being well-organized and not too much template bloat, then that would have been lovely.