I’m new to Julia development and was just trying out the following snippet:
`
function foo()::String
return 22
end
`
I expected LSP to have highlighted the code with error, because the return type of this function is String and I’m returning a number from this function but I see no squiggly lines or any error in VSCode.
Does anyone know why LSP is not flagging this as error?
Also note that this is slightly tricky, because someone can always define the appropriate convert method somewhere
julia> function foo()::String
return 22
end
foo (generic function with 1 method)
julia> foo()
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String
Closest candidates are:
convert(::Type{String}, ::String) at essentials.jl:218
convert(::Type{T}, ::T) where T<:AbstractString at strings/basic.jl:231
convert(::Type{T}, ::AbstractString) where T<:AbstractString at strings/basic.jl:232
...
Stacktrace:
[1] foo()
@ Main ./REPL[64]:2
[2] top-level scope
@ REPL[65]:1
julia> Base.convert(::Type{String}, i::Int64) = string(i)
julia> foo()
"22"
To expand upon the answer from @pfitzseb, function return type declarations work by adding an implicit type conversion at the end of your function. It’s not a static guarantee, it’s a dynamic conversion, which could fail if the conversion fails. Julia is a dynamic language, after all.
Most of the time you should avoid annotating return types because it makes your functions less generic and because it relies on an implicit conversion. If you really need to convert the output of your function to String, then you might as well add an explicit conversion inside your function.
Quoting from the manual:
Return type declarations are rarely used in Julia: in general, you should instead write “type-stable” functions in which Julia’s compiler can automatically infer the return type.
I love how Julia is filling this niche of scientific/numerical computing really well
I think one of the ways to make the best use of the rich type system is to warn the user as early in development cycle as possible
My thinking is every single “compile” error that I get when I run the code, I could’ve gotten earlier, had an automation run it in advance for me.
Also for my own personal use-cases(which are very narrow scoped), I start out by very strictly defining functions args and their return types, because that is how I’ve modelled the problem in my mind.
@CameronBieganek@pfitzseb What would be a good place to introduce this check that I was looking for? Basically get a warning that my function return is not the same as my function return annotation. Would it be LanguageServer.jl or JET.jl? I could take a stab at it.
JET already happily handles this case (with full VS Code support):
You still need to explicitly ask for it to analyze your code though, because currently there’s no way we can automatically do that analysis in realtime.
Basically get a warning that my function return is not the same as my function return annotation. Would it be LanguageServer.jl or JET.jl? I could take a stab at it.
We could potentially add that to LanguageServer.jl (well, StaticLint.jl to be precise), but it requires good type analysis, which we don’t currently have. The toy example is probably reasonably easy to throw a warning for, but anything more complex is unlikely to work.