Yeah, I mean thereās nothing wrong with it, itās just not a common pattern people do in package code from my experience, so I see why it can trip people up or confuse them.
Hmm, no this still isnāt right. From the manual:
When x = occurs in a local scope, Julia applies the following rules to decide what the expression means based on where the assignment expression occurs and what x already refers to at that location:
Existing local: If x is already a local variable, then the existing local x is assigned;
Hard scope: If x is not already a local variable and assignment occurs inside of any hard scope construct (i.e. within a let block, function or macro body, comprehension, or generator), a new local named x is created in the scope of the assignment;
So the first line of a let is āharder than hardā. And the only ways to get this nameless āsuperhard scopeā seem to be
The let construct is traditional, but it does two technically unrelated things which would perhaps be better disentangled:
Create a local scope
Create new bindings for a set of names in that scope
We can imagine a scope ... end construct that just does the first. Then you could translate
let a = 1, b = 2
c = 3
# stuff
end
to this:
scope
local a = 1
local b = 2
c = 3
end
So a and b are new locals in the let block no matter what, whereas c follows the normal scope rule: if there is already a local named c it is assigned, if there isnāt then it is created in this scope. Arguably it would be cleaner to keep these orthogonal, but let is traditional and allows you to do both together.
You may already be aware of this, but the easier way to write
function f()
a = 1
b = 2
c = let
local a = 3
local b = 4
a+b
end
(a, b, c)
end
is like this:
function f()
a = 1
b = 2
c = let a = 3, b = 4
a + b
end
(a, b, c)
end
I donāt know if itās been made clear yet or not, but the purpose of the let block that you linked to in SymbolicUtils.jl is to create closures. The other option is to use global constants:
const d = Dict(1 => 11, 2 => 12)
function foo(x)
if x > 0
x + d[1]
else
x + d[2]
end
end
In fact, Iāve been wondering for a while now if thereās any advantage to
let
d = Dict(1 => 11, 2 => 12)
global function foo(x)
if x > 0
x + d[1]
else
x + d[2]
end
end
end
over the version with a global constant, aside from reducing namespace clutter. But I guess thatās a little off topic.
Thanks, yes Iām aware of this. The point was that if we have many bindings or much longer ones, this gets very awkward. The natural solution I could see is to allow let begin. Maybe this could be allowed at some point.
Comma-separated assignments also strike me as strange. But it reminds me a little of named tuples. So I could also imagine being able to do
julia> nt = (a=1,b=2)
(a = 1, b = 2)
julia> let nt...
a+b
end
My understanding is that there arenāt many times when you need a let block in Julia. As far as I know, there are two main use cases for let blocks:
Creating closures at the top-level, like in the SymbolicUtils example.
Shenanigans where you are creating closures in a while block.
Of course, the other use is just to create a local scope with some local bindings, but given that the Julia style is to write lots of small functions, I havenāt really found myself needing let blocks for that.
I had another use case in mind. For metaprogramming, itās nice to be able to generate code thatās a little more readable. If weāre doing this in a purely functional way, itās nice to have a guarantee that a generated Expr can be inserted anyway without affecting values outside its context.
Oh, thatās very nice. Thanks for pointing that out!
Another case when let blocks are helpful is notebooks, both jupyter and pluto. let is a convenient way to have variables local to a cell that donāt pollute āglobalā namespace.
I think this would be an excellent syntax addition. Itās also not something you can implement with macros without introducing type instability, see this discussion thread.
Simon, do you mind explaining how itās fundamentally incompatible? I keep learning more about how Julia operates though explanations by you, Steven and so many others.