I looked at the joinpath code but couldn't tell why it had no problem using
AbstractString to accept UFT8String or ASCIIString.
joinpath(a::AbstractString) = a
joinpath(a::AbstractString, b::AbstractString, c::AbstractString...) =
joinpath(joinpath(a,b), c...)
function joinpath(a::AbstractString, b::AbstractString)
isabspath(b) && return b
A, a = splitdrive(a)
B, b = splitdrive(b)
!isempty(B) && A != B && throw(ArgumentError("drive mismatch: $A$a $B$b"
))
C = isempty(B) ? A : B
isempty(a) ? string(C,b) :
ismatch(path_separator_re, a[end:end]) ? string(C,a,b) :
string(C,a,pathsep(a,b),b)
end