Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve return type inference for string #52806

Merged
merged 1 commit into from
Feb 7, 2024

Conversation

nsajko
Copy link
Contributor

@nsajko nsajko commented Jan 8, 2024

Packages like URIs.jl overload joinpath with methods that return non-strings. This prevents good return type inference for string when the types of its arguments are unknown. Even if this is a URIs.jl bug, it makes sense to be defensive about this in the Julia implementation. Also note that URIs.jl is widely-used, JuliaHub says it's got in excess of a thousand (indirect) dependents.

So, IMO, this is a Julia bug that we should fix:

julia> all(T -> T <: AbstractString, Base.return_types(string))
true

julia> import URIs

julia> all(T -> T <: AbstractString, Base.return_types(string))
false

Fixed by adding a ::String type assertion in base/libdl.jl.

Packages like URIs.jl overload `joinpath` with methods that return
non-strings. This prevents good return type inference for `string`
when the types of its arguments are unknown. Even if this is a URIs.jl
bug, it makes sense to be defensive about this in the Julia
implementation. Also note that URIs.jl is widely-used, JuliaHub says
it's got in excess of a thousand (indirect) dependents.

So, IMO, this is a Julia bug that we should fix:

```julia-repl
julia> all(T -> T <: AbstractString, Base.return_types(string))
true

julia> import URIs

julia> all(T -> T <: AbstractString, Base.return_types(string))
false
```

Fixed by adding a `::String` type assertion in `base/libdl.jl`.
@@ -334,7 +334,7 @@ struct LazyLibraryPath
LazyLibraryPath(pieces::Vector) = new(pieces)
end
LazyLibraryPath(args...) = LazyLibraryPath(collect(args))
Base.string(llp::LazyLibraryPath) = joinpath(string.(llp.pieces)...)
Base.string(llp::LazyLibraryPath) = joinpath(string.(llp.pieces)...)::String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is a good idea, but if you want to do it, it should be a return type declaration, so

Suggested change
Base.string(llp::LazyLibraryPath) = joinpath(string.(llp.pieces)...)::String
Base.string(llp::LazyLibraryPath)::String = joinpath(string.(llp.pieces)...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is a good idea

Why would it be anything but good? There's basically no downside. In case the check is useless, it will get optimized out, otherwise it's useful because it helps contain type-instability.

if you want to do it, it should be a return type declaration

Why? As far as I see the expression joinpath(string.(llp.pieces)...) is required to be a String, not just convertible to String, so I don't see a good reason for introducing conversion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @nsajko

Copy link
Contributor

@fingolfin fingolfin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

@vtjnash vtjnash merged commit 76b8b2a into JuliaLang:master Feb 7, 2024
7 checks passed
@nsajko nsajko deleted the libdl_string branch February 7, 2024 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants