If I define a variable b in Main and then use the let block:
b = 5
let
b = b
println(b)
end
I get the error saying: " UndefVarError: b not defined"
I can get this to work by doing:
b = 5
let
b = Main.b
println(b)
end
Is there a way to do this which doesn’t use Main but instead whatever level this was called in? In other words if I did this within a function, then I wouldn’t want to use the word Main.
I tried using the escape function but wasn’t successful.
When defining multiple variables in a let block, I tend to favor the following syntax (which I learned about here on Discourse, too). In the line of the let keyword, I only list the variables to be given a local scope, without their assigned values. And then, in the first fiew lines of the body of the let block, I assign their values. E.g.,
global_value = let x, y
x = <expression-to-compute-x>
y = <expression-to-compute-y>
<expression-using-x-and-y>
end
Yes, but only in the first line of the let block do you have the ability to create a new binding for an existing variable, while still referring to that variable for the assigned value. (And this was precisely the use case mentioned in the OP).
Consider the following example:
julia> x = 1
1
# in the lhs, x refers to a new binding
# in the rhs, x refers to the global variable
julia> let x = x + 1
x *= 2
end
4
julia> x
1
but
julia> x = 1
1
julia> let x # <- new binding introduced here, shadows the global variable everywhere in the let body
x = x + 1 # x refers to the new variable in both lhs and rhs
x *= 2 # => ERROR
end
ERROR: UndefVarError: `x` not defined
Stacktrace:
[1] top-level scope
@ REPL[4]:2
Fair point. If you need to use the values of some shadowed variables, you have no other option than to use them in the first line of the let block. I don’t like rebinding variables, though, so this is usually not an issue for me.
Because let creates a local scope and assignments in local scopes create a new binding. If you only used x inside the let block then you’d get the global value. But in any case you cannot overwrite it globally without using global x somewhere.
Your are right of course. Here x is already a local binding - just not local to the let-block (which I honestly find a bit confusing). Arguably that is the default mode of operation for let and what I posted a special case for true global variables.
I think, I just interpreted the @greg_plowman’s code to be in global scope due to the variable named global_value.
My package Handcalcs.jl can find functions and “unpack” the lines in the function into the current scope. See here. But I don’t actually want to introduce those variables into the current scope, so I wrap them in a let block.
lets say I have a function:
function my_add(a, b)
c = a + b
end
If I write something like:
a = 2
b = 3
@handcalcs c = my_add(a, b)
The handcalcs macro will turn this into something like:
c = let (a, b) = (a, b)
c = a + b
end
There is more going on in the macro but this was the intent of the question. When the parameter names happen to be variables names in the current scope, the let block will not see the variables in the current scope so it needs to be in the first line rather than the second part of the let block.