`+` not defined!?

I’m new to Julia but this error message has me thinking its not even worth trying. This code:

using Plots

x= 2.0
y=9.0

dx = 0.1
dy = -0.1

plot((x,y),
xlim = (0,10.0),
ylim = (0,10.0),
markershape=:o)

function update(x,y)
x = x + dx,
y = y + dy,
plot!((x,y))
end

update(x,y)

Gives me an error ERROR: UndefVarError: + not defined.

Google shows nothing. How is anyone supposed to start a new language if this is the kind of errors that occur?

Welcome! Yes, that’s an unusually bad error message.

The trailing commas there are your problem; they’re mixing up all your assignments in the update function (the mixup is making Julia think you’re defining your own + method). Commas are only used to separate function arguments and list elements, not lines of code.

12 Likes

thanks! please forgive my frustration

I’d like to make a proposal for Julia 2.0: it should be illegal to define named functions except at the outermost level of the containing function (or module). This will prevent many baffling error messages, and it will also prevent new users from making mistakes like:

function outer(x)
if x > 0
   function nested()
       3
   end
else
  function nested()
       4
  end
end
end

You definitely don’t want that restriction at a module, conditional method definitions there are fine and useful. You probably don’t want that restriction in a function either because not every block is conditional and will work fine e.g. let inner=3; foo() = inner end, and loops for capturing variables don’t override methods so those are fine e.g. for inner in 1:3 foo() = inner end. Basically you’re fine if you don’t write multiple nested definitions for the same method signature (prints warning), and you can’t really conditionally define any nested method even if it’s just for capturing variables (doesn’t print warning). On a practical level, it is still easier to write more complicated method headers in the named function syntax than in the anonymous function syntax. I don’t think this work needs to wait for 2.0, issue 15602 already exists for this and is where serious thought-out proposals should go. Turns out figuring out when nested method definitions are wrong is not so clear-cut.

2 Likes

I agree with you that at the module level, it makes sense to allow conditional named-function definition. So I retract that part of my proposal.

However, I am not convinced that defining named functions inside nesting levels that are inside another function is a useful feature of the language. It is possible to accomplish the same goal using anonymous functions (e.g. let inner=3; foo = () -> inner; end) without as many pitfalls. Thanks for pointing out the github issue. Here are other issues about this. All these issues would go away if nested definitions of named functions were banned.

Infix operator definition syntax needs documentation · Issue #15483 · JuliaLang/julia (github.com) and

misleading error message for misplaced = sign (disallow function definitions in argument position) · Issue #17730 · JuliaLang/julia (github.com)

1 Like

I like local functions. They’re useful enough that they were added to C# several years ago.

Sometimes it’s the most logical, easiest way to break down a complex function into parts, without polluting the namespace with functions that don’t matter anywhere else.

#17730 is invalid syntax in 1.10 now

#15483 is tricky but the issue is about how it’s possible to accidentally define a function with an operator, not where that definition is located. In that case, I think it would make sense to not allow operator-like function definitions inside other functions.

1 Like

Just to be clear: I am not opposed to local functions. Rather, I am opposed to named local functions that lie inside a syntax nesting that is inside the outer function. In other words, I am OK with both of the following

   function outer()
       function inner()
       end
   end

and

function outer(a)
    f = a > 0 ? () -> 4 : () -> 5
end

but I believe that code like the OP’s that redefined + should be banned.

2 Likes

It seems like a footgun that it’s possible to define methods using infix notation. I suppose it would be breaking to remove (maybe only a “minor” change? do people really use that pattern on purpose?), but it doesn’t seem very useful because (from the 90 seconds I’ve spent on it) one can’t add dispatch types to infix definitions. So either you’re defining an available-but-unused operator on ::Any inputs (fine, although maybe not that common and call syntax is still available), pirating (shame on you), or making a mistake. EDIT: it looks like you can declare dispatch types, although it will still shadow the Base operator if you don’t import <the_operator> or qualify it as Base.:<the_operator>.

EDIT: It looks like there’s been some discussion on this topic happening for a while now, e.g. #15483, with some in favor and some against (even among influential devs). Unless opinions have shifted to dominantly unfavorable, I think it’d be difficult to change the state of infix definitions.

2 Likes

There was a posting a few years back on this forum about another instance of an errant function definition caused by a statement like this buried deep inside an outer function:

   assert(length(v)=n)

The error message produced was something like length(::Vector{...}) is undefined. The line that generated the error message was far away from incorrect assert statement. So it is not just infix function definition that creates the problem.