Personally not a fan because it’s a lot of manual forwarding in new barebones methods with no consistency on what happens.
round is a special case because you very often want an integer result but you may also want to retain the input type for further work, so the output type does become a worthy input. But look at the forwarding work it does besides the actual rounding:
round(::Type{T}, x) where T = round(T, x, RoundNearest)
round(::Type{T}, x, r::RoundingMode) where T = _round_convert(T, round(x, r), x, r)
_round_convert(::Type{T}, x_integer, x, r) where T = convert(T, x_integer)
It complicates the method table to essentially mirror convert, and for the general case, it’s much simpler to do it ourselves when functions expect particular input types or when we want to process an output type, with no loss in clarity.
If all the BigInt input would do is convert the output’s type like round does, then it would not change the incorrect result’s value BigInt(sum(x -> x*x, s)). You can already specify a BigInt input, and it gives the wrong results because it only affects the accumulated value, not the overflow while processing the input iterable:
julia> sum(x -> x*x, s; init=BigInt(0))
0
Changing the input iterable BigInt.(s) or the elementwise function x -> BigInt(x)*x is necessary for evading overflow, and a BigInt input that does either automatically adds ambiguity about what happens. A user may even assume it’s only converting the output value’s type like convert or round does, with frustrating outcomes when they start tweaking code. Considering that the clearer code is the same amount of work, it’s worth doing in my opinion.