In the closures section there is only one example that is not clear enought to understand how to use closures in Julia.
Can you provide some explaination and also an example about the correct way to make pseudo-objects using clousures in Jula?
That section just describes closures in Julia, not the concept of closures in general and how to use them.
Perhaps you could explain what you are trying to do for more specific help.
Perhaps this example will help you. To make closures, I typically use a template that looks kind of like this
const binomsum = ( () -> begin
Y = Array{Int,1}[Int[1]]
return (n::Int,i::Int) -> (begin
for k â length(Y)+1:n
push!(Y,cumsum([binomial(k,q) for q â 0:k]))
end
i â 0 ? Y[n][i] : 0
end)
end)()
where Y[n][i]
is my cache of computed values, which I can access with binomsum(n::Int, i::Int)
. If the cache does not contain the values yet, it will automatically fill the cache up to that value.
I donât see anything wrong with your example.
If youâd like to relate it back to the example in the documentation you could rewrite your example as
function adder(Y)
return (n::Int,i::Int) -> (begin
for k â length(Y)+1:n
push!(Y,cumsum([binomial(k,q) for q â 0:k]))
end
i â 0 ? Y[n][i] : 0
end)
end
const binomsum = adder(Array{Int,1}[Int[1]])
Because the captured variable value is always the same, your example could also have been written as
function adder()
Y = Array{Int,1}[Int[1]]
return (n::Int,i::Int) -> (begin ... end)
end
const binomsum = adder()
And because you create const binomsum
only once, you donât need to name the outer function âadderâ.
An anonymous function is sufficient. The final result would be the same as your example.
I donât need the closures general concept but only a good way to make pseudo-object with closures in Julia, an example of one psudo-object with some methods and some attributes. Thanks
What is a pseudo-object?
This is an example with JS
But there are a lot way to do it in JS and I think also in Julia, but the link show a good way to do it in JS, Iâm looking for a good transaltion of that code in Julia
That link does not have a single use of âpseudo-objectâ and it contains a few different JS patterns so Iâm still not sure which one exactly you are talking about.
FWIW, the problems (and solutions) mentioned in that post is very js specific (this
is dynamically scoped) so thereâs pretty much no (need for a) solution to a non-existing problem.
Also, most the ingredients used, (defining contructor, closure that captures local variable, calling constructor) are all well defined and documented syntax in julia so you need to be clear which one you are asking about (you doesnât seem to be looking for a closure only example). Also, not all code are translatable due to julia not having a dynamically scoped this
and, again, requires better clarification of your actual question.
Also note that julia objects are not just a different spelling of Dict
with String
as keys (as is the case in js) and all fields in julia are typed. These can affect the usefulness of some of the code in that post in a subtle way (e.g. the problem may not exist, the solution is not good practice, or a mixed of these with possibly other issues).
P.S. I thought the canonical way to define a OOP object is via prototypeâŚ
Juliaâs object model is very different than JavaScriptâs. Methods are defined on the type signatures of functions, not objects (as in this strange article) nor on prototypes (as in normal JavaScript).
- Julia methods are never bound to instances.
- Any concrete objects available in a Julia function are sent as arguments or defined in an outer scope.
- In JavaScript, new objects are derived from other objects (prototypes). In Julia objects are instances of structs (or primatives).
- In JavaScript, a new prototype can be defined at any point during execution, in any context. In Julia, structs can only be defined at the top-level scope and are analyzed at compile-time.
If you are determined to use this pattern in Julia, you could do something like this:
function badobject(foo, bar, baz)
Dict(
"addtofoo" => function(x)
foo + x
end,
"subtractfrombar" => function(x)
bar - x
end
)
end
However, this is not good Julia! Define methods for your structs as regular functions and pass objects to them as needed. Just use closures for the normal stuff: currying and/or allowing a single function to keep private state between calls.
Using a dictionary like this will be much slower than using structs and functions. Part of the reason Julia is so fast is that its object system allows much more efficient data allocation. Most structs can be compiled to contiguous data blocks in memory. Emulating JavaScript patterns with dictionaries in Julia will make your code much slower. In fact, it will probably be even slower than the equivalent JavaScript, since the Julia JIT is targeted at making the most of statically analyzable structs, and JavaScript runtimes have to be more adapted to the ubiquity of lookup tables.
I donât think I can help you without some context, and a description of what you are trying to achieve, instead of an example of what someone does in JS, which is a completely different language.
Encapsulating state with closures is a cute exercise, and you can also do that in Julia, but in practice it is not necessary.
This explains so much! Closures come up a bunch in discussions here, and Iâve read that bit of the docs, but still have no idea what they are or what theyâre for. Anyone know of any good resources that explains the concept of closures in general and how to use them?
So, you have a function that returns a function.
mkadder(x) = y -> x + y
add3 = mkadder(3)
add3(2) == 5
# true
add4 = mkadder(4)
add4(5) == 9
# true
# add3 still works the same
add3(8) == 11
# true
add3 and add4 are closures. They are functions that carry along the values in the scope where they were created.
This is a good alternative to using globals. For example, one can speed up the slow recursive fibonacci calculation this way, by caching results between calls, but without having to rely on global state.
function fib(num::Real)
cache = typeof(num)[1, 1]
function inner(n)
if length(cache) >= n
return cache[n]
else
push!(cache, inner(n-1) + inner(n-2))
return cache[n]
end
end
inner(num)
end
for i in 1:10:50
println(fib(i))
end
output:
1
89
10946
1346269
165580141
Caching increases the speed of naive recursive fibonacci from O(2^n) to O(n). State is bad, but it helps sometimes. Closures help keep the state private. Closures can also be used as an alternative way to implement lazy evaluation.
function counterto(n)
count = 0
return () -> (count >= n ? nothing : count += 1)
end
tencount = counterto(10)
while (n = tencount()) != nothing
println(n)
end
output:
1
2
3
4
5
6
7
8
9
10
In this example, you use a closure that will return the next value every time you call it, which is useful for creating a qick-and-dirty iterator pattern (generating values as needed, rather than all at once. Saves memory). In Julia, youâd normally implement an iterate
method, but that requires creating a special struct. The other way people sometimes do this in Julia is with Channels. Iâm not sure which is preferable, though the Channel pattern does look a little cleaner to my eye.
Heh, yeah - you could have done lmgtfy too. I actually did read that before - it wasnât a ton of help. Wikipedia articles are great if you understand like 85% if the jargon, but Iâve never taken a cs class and there are some pretty glaring gap in my understanding. I do what I can with Wikipedia and nested stack overflow searches. I actually learned a ton from the Julia manual and googling the things in there I didnât understand, though closures were still a black box until the past below yours.
I wish I had more hearts to give! Super clear now, and Iâm bookmarking for later review. Thanks!
Sounds like you are complaining about me posting a link to wikipedia because you find it hard to read. I actually thought the wikipedia article had a nice existing explanation, so I figured itâs worth noting.
Closures are amazingly powerful and can be used to implement a variety of useful constructs, including objects that encapsulate and continuation-like constructs. Demoing this is part of every self-respecting book on Lisp dialects.
While all of these things are possible with closures in Julia, too, in most cases it is more idiomatic to use a first-class representation, eg a composite type, which you can make it callable. It pretty much amounts to the same compiled code (in the ideal case), but makes debugging, documentation, and extensions easier.
The most important practical application of closures is higher-order programming, ie using functions as arguments. Eg
julia> filter(x -> x % 3 == 0, 1:10)
3-element Array{Int64,1}:
3
6
9
Not complaining . No hard feelings - just didnât want to leave the impression that I hadnât put in some minimal effort before posting asking for resources.
Neat - I actually do this all the time with filter
and map
especially, didnât realize it was related.