Why does scientific notation break the range function?

I think this is true for older versions of Matlab. Nowadays there are, e. g., 16 bit integer arrays. Probably a value like 1000 by default still becomes a 1x1 double matrix, but you could force it to be a 1x1 int16 matrix.

Integer types have existed in Matlab for quite long but literals (e.g. 1000) are doubles, so it would be unreasonably inconvenient to require integer types to be used as arguments to common functions, not to speak of backwards compatibility issues with changing it.

4 Likes

For what it’s worth, LinRange gives a better stacktrace (and is a cleaner drop-in replacement for linspace):

julia> LinRange(0, 1, 1e3)
ERROR: MethodError: no method matching LinRange(::Int64, ::Int64, ::Float64)
Closest candidates are:
  LinRange(::Any, ::Any, ::Integer) at range.jl:563
Stacktrace:
 [1] top-level scope
   @ REPL[14]:1

julia> range(0, 1, length=1e3)
ERROR: TypeError: in keyword argument length, expected Union{Nothing, Integer}, got a value of type Float64
Stacktrace:
 [1] top-level scope
   @ REPL[15]:1
1 Like

The Julia community is very particular in this sense, as any post here gets answers from newbies, relatively new users, computer engineers working at Julia Computing, language founders, world-class computer scientists, all together. And many of the new questions bring back heated discussions of the past, but even then it is curious that it is common that we can find and link the issue in github where the decision was taken, sometimes, as here, many many years ago.

Nobody knows, at the same time, the background of the poster. So he/she maybe someone with a strong background in computer sciences, or someone that is just starting to script something. I have more than once answered a question and, later, realized that the poster was someone with a much more deep knowledge of the question than me. Probably having to read my answer was irritating. And the same thing goes otherwise, sometimes people get answers here that are way far from what they have as a background. The good thing is that with some persistence the amount we learn about computer and programming is huge.

24 Likes

What about when you do floating point calculations to come up with the indices, isn’t that likely to lead to small rounding errors so that the exact integers aren’t hit exactly? For example when doing divisions with divisors that are not powers of two.

No, it’s terrible! The “useful” part of the error message, Union{Nothing, Integer} is a far too cryptic way to say, “Hey buddy, use a dang Integer instead of a Float!”

And I’m not trying to be a troll here, but I actually still can’t mentally parse what Union{Nothing, Integer} is actually saying. All users can do is try to figure it out from the words that are there. I tried entering it into the REPL and it returned Union{Nothing, Integer}. I tried searching the help docs for Nothing because that part is very confusing, and this is what I got:

help?> Nothing
search: Nothing nothing isnothing

  Nothing

  A type with no fields that is the type of nothing.

  See also: isnothing, Some, Missing.

Sorry to revert back to insults, but it’s a lousy, no-good error message! :slight_smile:

3 Likes

FWIW, here is an example of a TypeScript error message for union types

Argument of type 'boolean' is not assignable to parameter of type 'string | number'.

Off the top of my hat the following type constructions could be problematic, too: Tuple, Vararg, UnionAll.

If you want to take a look into the machinery.

TypeError: in keyword argument length, expected Union{Nothing, Integer}, got a value of type Float64
  • TypeError: The error is about the type of something in the function,
  • in keyword argument length: This is where there is some type error, in the length argument,
  • expected Union{Nothing, Integer}, got Float64: there’s your “Hey buddy”! It told you what was expected and then what it got.

I appreciate that the whole Union part may not be so obvious, but by googling* Julia Union you get a pretty good explanation + example of what a Union type would mean.

*Really shouldn’t have to do that, but tbh I’m just lazy so I google everything

5 Likes

Doesn’t even need google:

help?> Union
(...)

  Union{Types...}

  A type union is an abstract type which includes all instances of any of its argument types. The empty union Union{} is the bottom type of Julia.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> IntOrString = Union{Int,AbstractString}
  Union{Int64, AbstractString}

  julia> 1 :: IntOrString
  1

  julia> "Hello!" :: IntOrString
  "Hello!"

  julia> 1.0 :: IntOrString
  ERROR: TypeError: in typeassert, expected Union{Int64, AbstractString}, got a value of type Float64

which coincidentally is almost exactly the error message that OP saw.

7 Likes

So, good, but not stellar? :wink:

But, replace Union{} with Integer, and I don’t really see how to improve it further. Maybe you have a suggestion?

2 Likes

oh, lets be open minded here with the people just arriving to the language… There is a lot technical information in that phrase. Understanding that occurs not at the same point in Julia programming than when doing some scripts to analyze data series and plots.

(myself included, I barely understand what the “The empty union … is the bottom type of Julia” means, I remember hearing something about it from a presentation at JuliaCon about the type system and now can sort of reason about it, but I’m far to really being able to explain that)

11 Likes

FWIW, Racket has language levels.

3 Likes

I’d start by identifying that the error occurs in the range function, because that’s the first thing people will want to know (yet it doesn’t appear anywhere in the current error message). Then I’d zero in on exactly where the error is within the range function, say what caused it, and conclude with some constructive advice on possible ways to fix the error.

That’s the order that people will want to process the information, and it’s the order the information should be presented in. I’d also write it in human language (a sentence) rather than a series of cryptic sentence fragments. Here’s my suggested rewrite:

ERROR in range(): Keyword argument length was entered as type Float64, but must be of type Integer.
1 Like

I believe this is a slight misconception: the problematic part in stack traces is in most cases the uppermost caller and not the lowermost callee.

What? Where in this Stacktrace does it say the error is in the range function?

Stacktrace:
  [1] top-level scope
    @ ~/Documents/coursework/Untitled-1.ipynb:1
  [2] eval
    @ ./boot.jl:373 [inlined]
  [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
    @ Base ./loading.jl:1196
  [4] #invokelatest#2
    @ ./essentials.jl:716 [inlined]
  [5] invokelatest
    @ ./essentials.jl:714 [inlined]
  [6] (::VSCodeServer.var"#164#165"{VSCodeServer.NotebookRunCellArguments, String})()
    @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.6.17/scripts/packages/VSCodeServer/src/serve_notebook.jl:19
  [7] withpath(f::VSCodeServer.var"#164#165"{VSCodeServer.NotebookRunCellArguments, String}, path::String)
    @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.6.17/scripts/packages/VSCodeServer/src/repl.jl:184
  [8] notebook_runcell_request(conn::VSCodeServer.JSONRPC.JSONRPCEndpoint{Base.PipeEndpoint, Base.PipeEndpoint}, params::VSCodeServer.NotebookRunCellArguments)
    @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.6.17/scripts/packages/VSCodeServer/src/serve_notebook.jl:13
  [9] dispatch_msg(x::VSCodeServer.JSONRPC.JSONRPCEndpoint{Base.PipeEndpoint, Base.PipeEndpoint}, dispatcher::VSCodeServer.JSONRPC.MsgDispatcher, msg::Dict{String, Any})
    @ VSCodeServer.JSONRPC ~/.vscode/extensions/julialang.language-julia-1.6.17/scripts/packages/JSONRPC/src/typed.jl:67
 [10] serve_notebook(pipename::String, outputchannel_logger::Base.CoreLogging.SimpleLogger; crashreporting_pipename::String)
    @ VSCodeServer ~/.vscode/extensions/julialang.language-julia-1.6.17/scripts/packages/VSCodeServer/src/serve_notebook.jl:136
 [11] top-level scope
    @ ~/.vscode/extensions/julialang.language-julia-1.6.17/scripts/notebook/notebook.jl:32
 [12] include(mod::Module, _path::String)
    @ Base ./Base.jl:418
 [13] exec_options(opts::Base.JLOptions)
    @ Base ./client.jl:292
 [14] _start()
    @ Base ./client.jl:495

That part will be improved by Why does scientific notation break the range function? - #25 by pfitzseb, but it looks like even with that change it’s missing the entry for the logrange function itself.

The MWE

function test(start, stop, length)
    range(start, stop, length=length)
end    

test(1, 2, 0.42)

yields

ERROR: TypeError: in keyword argument length, expected Union{Nothing, Integer}, got a value of type Float64
Stacktrace:
 [1] test(start::Int64, stop::Int64, length::Float64)
   @ Main 1.jl:2
 [2] top-level scope
   @ 1.jl:6

and yes you are right: the reference to range is missing…

But I would still search the problem either on top-level or in test

1 Like

Whaaa? How on earth is range missing from the trace? I didn’t even notice that.

Anyone know why that happens?

5 Likes

Well I guess the error is not in the range function so it makes sense that it’s not part of the stack trace.
Nevertheless, it would be nice if the error message would mention range.

A note on some relevant part of the julia documentation. It says

Keyword arguments behave quite differently from ordinary positional arguments. In particular, they do not participate in method dispatch. Methods are dispatched based only on positional arguments, with keyword arguments processed after the matching method is identified.

I think this part could be a bit more specific, i.e. it could mention how keyword arguments are processed after the matching method is identified. The way I understand it, type annotations on keyword arguments are just type assertions.

If above understanding is correct, the type assertion is probably a generic error message in base julia, which likely could easily be modified to print out the method that was identified in the preceding dispatch.

4 Likes

Relevant issue: better error for passing wrong type of keyword argument · Issue #29829 · JuliaLang/julia · GitHub
Seems like the function/method name used to be part of the error message, but was changed. According to a comment by Jeff on the linked issue this should be part of the stack trace.
I’m confused now :sweat_smile:

Edit:
here is how the error message is formed. It has a special case for TypeErrors from keyword arguments. This is a bit weird, but I guess there was a deeper reason for that related to above issue.

3 Likes