Using Rust, Typescript, Kotlin, and Swift for inspiration, this could be:
def hostname(%URI{host: host} :: URI | String?) :: String?, do: host
def hostname(url :: URI | String?) when is_binary(url) :: String?, do: hostname(URI.parse(url))
def hostname(nil :: URI | String?) :: String?, do: nil
And now there’s no question of readability, which furthers my point: modern languages have already solved this elegantly and concisely.