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:
1) .to!string of the first argument
2) .to!int of th 2nd argument
3) implementing int.opCmp(string)
4) 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.