The following code is a simplification of a code of a library I'm working on. The code runs but it does not produces the expected output. The problem turns out to be the use of a wrong variable name (k instead of c) in the function fn. However, no error was not reported.
fn(ch, c) = put!(ch, k)
chnl = Channel{Char}(1)
function producer(ch,str)
for c in str
fn(ch, c)
end
end
consumer(ch) = for c in ch
print(c)
end
Threads.#spawn producer(chnl, "Hello World!\n")
Threads.#spawn consumer(chnl)
sleep(1)
println("Done")
Detecting this problem took me a while on the original code, because no error was reported. Is there something I could use to detect this type of problem in the future, specially because function fn is suppose to be written by the user?
seems to produce error for me:
julia> Threads.#spawn producer(chnl, "Hello World!\n")
Task (failed) #0x00007fccc68cc160
UndefVarError: k not defined
changing this to:
t1 = Threads.#spawn producer(chnl, "Hello World!\n")
t2 = Threads.#spawn consumer(chnl)
wait(t1)
wait(t2)
println("Done")
running as a script:
akako#ThinkX /tmp> julia test.jl
ERROR: LoadError: TaskFailedException
Stacktrace:
[1] wait(t::Task)
# Base ./task.jl:322
[2] top-level scope
# /tmp/test.jl:17
nested task error: UndefVarError: k not defined
Stacktrace:
[1] fn(ch::Channel{Char}, c::Char)
# Main /tmp/test.jl:1
[2] producer(ch::Channel{Char}, str::String)
# Main /tmp/test.jl:7
[3] (::var"#1#2")()
# Main ./threadingconstructs.jl:169
After digging a little bit more, an alternative solution is to wrap the body of the function producer in a try-catch statement
function producer(ch,str)
try
for c in str
fn(ch, c)
end
catch
for (exc, bt) in Base.catch_stack()
showerror(stdout, exc, bt)
println(stdout)
end
exit()
end
end
Resulting in a stack race of the problem:
/tmp> julia problem.jl
UndefVarError: k not defined
Stacktrace:
[1] fn(ch::Channel{Char}, c::Char)
# Main /tmp/problem.jl:1
[2] producer(ch::Channel{Char}, str::String)
# Main /tmp/problem.jl:8
[3] (::var"#1#2")()
# Main ./threadingconstructs.jl:169
Related
The script is really simple, and it is stored in a file named 001.jl
sum = 0
for i in 1:10-1
if i%3 == 0 || i%5 == 0
sum = sum + i
end
end
println("The sum is ", sum)
Nevertheless when I try to run it in the console I get this error
ERROR: LoadError: UndefVarError: sum not defined
Stacktrace:
[1] top-level scope at /Users/aceves/Documents/MyScripts/julia/001.jl:5 [inlined]
[2] top-level scope at ./none:0
[3] include at ./boot.jl:317 [inlined]
[4] include_relative(::Module, ::String) at ./loading.jl:1044
[5] include(::Module, ::String) at ./sysimg.jl:29
[6] include(::String) at ./client.jl:392
[7] top-level scope at none:0
in expression starting at /Users/aceves/Documents/MyScripts/julia/001.jl:3
Runs perfectly with julia 0.6 though. It also works if I type exactly that in the REPL of the 1.0.2 version. I'm obviously missing one detail. does anyone has an idea which?
Like it was said in the comments the problem is in scoping change in Julia 1.0.
It should be noted that in many examples such as this the simplest and fastest solution is surrounding all your code within a single let block. The let block introduces a local scope:
let
sum = 0
for i in 1:10-1
if i%3 == 0 || i%5 == 0
sum = sum + i
end
end
println("The sum is ", sum)
end
I read such a minimal demonstration about coroutine A Curious Course on Coroutines and Concurrency
def countdown(n):
print("Counting down from", n)
while n > 0:
yield n
n -= 1
#why it stop?
x = countdown(10)
#no output was produced
I print no result, when first call it.
In [10]: x
Out[10]: <generator object countdown at 0x1036e4228>
but should
In [14]: next(x)
Out[14]: Counting down from 10
In [15]: next(x)
Out[15]: 1
In [16]: next(x)
Why print("Counting down from", n)not executed directly when i invoke the function countdown().
I think the Counting down from 10 should be executed whatever yield, it is a sequential process.
What stop print("Counting down from", n) running, I am aware that
do something yield
yield will stop the action ahead of it,
but in the countdown example, how could yield stop print("Counting down from", n) by penetrating the while loop
If I understand your question correctly, you expect to see the Counting down from 10 text printed out immediately when you call countdown(10). But that reflects a misunderstanding of how generator functions work.
A yield expression isn't something that just interrupts the control flow of a normal function. Rather, any function that contains a yield anywhere in it becomes a generator function, which works differently than a normal function.
When you call a generator function, none of its code runs immediately. Instead, Python just creates a generator object that encapsulates the state of the function call (which at first will just record that you're at the very top of the function which hasn't started running yet). The generator object is what gets returned to the caller.
It is only after you call next on the generator object that function's code starts to run. It will run until it comes to a yield expression, and the value being yielded is what the next will return. The state of the running function is saved as part of the generator object, and it remains paused until you call next on it again.
The important thing to note is that the generator object doesn't ever run ahead of a yield until the outside code is done with the yielded value and asks for another one. We use generator functions specifically because they are lazy!
Here's a simple script that might help you understand how it works better than your example generator that tries to do something more useful:
import time
def generator_function():
print("generator start")
yield 1
print("generator middle")
yield 2
print("generator end")
print("creating the generator")
generator_object = generator_function()
print("taking a break")
time.sleep(1)
print("getting first value")
val1 = next(generator_object)
print("got", val1)
print("taking a break")
time.sleep(1)
print("getting second value")
val2 = next(generator_object)
print("got", val2)
print("taking a break")
time.sleep(1)
print("try getting a third value (it won't work)")
try:
val3 = next(generator_object) # note, the assignment never occurs, since next() raises
print("got", val3) # this line won't ever be reached
except Exception as e:
print("got an exception instead of a value:", type(e))
The print statements from the generator will always appear between the "getting" and "got" messages from the outer code.
for i in 1:2
if i == 2
print(x)
end
if i == 1
x = 0
end
end
UndefVarError : x not defined
Why does the code gives that error instead of printing 0 in julia?
While in python the following code print 0?
for i in range(2):
if i==1:
print(x)
if i==0:
x=0
The reason is because in the loop a variable gets a new binding each time a loop is executed, see https://docs.julialang.org/en/latest/manual/variables-and-scoping/#For-Loops-and-Comprehensions-1.
In fact while loop changed this behavior between Julia 0.6.3 and Julia 0.7 (in Julia 0.6.3 a new binding was not created). Therefore the following code:
function f()
i=0
while i < 2
i+=1
if i == 2
print(x)
end
if i == 1
x = 0
end
end
end
Gives the following output.
Julia 0.6.3
julia> function f()
i=0
while i < 2
i+=1
if i == 2
print(x)
end
if i == 1
x = 0
end
end
end
f (generic function with 1 method)
julia> f()
0
Julia 0.7.0
julia> function f()
i=0
while i < 2
i+=1
if i == 2
print(x)
end
if i == 1
x = 0
end
end
end
f (generic function with 1 method)
julia> f()
ERROR: UndefVarError: x not defined
Stacktrace:
[1] f() at .\REPL[2]:6
[2] top-level scope
For-loop created a new binding already in Julia 0.6.3 at each iteration so it fails both under Julia 0.6.3 and Julia 0.7.0.
EDIT: I have wrapped the examples in a function, but you would get the same result if you executed the while loop in global scope.
Ignore my comment andgo with Bogumil's answer as that's is the real rwason why your x variable disapears in thesecond iteration.
If you want your code to work like in Python, you can add the global keyword to your assignment of x:
for i in 1:2
if i == 2
print(x)
end
if i == 1
global x = 0
end
end
Note that this is not recommended in most cases as it'll make your code performance suffer. Julia likes local variables that the compiler can optimise away easily.
I'm trying to understand why the first main does not terminate when c is not valid, while the second terminates. From the description here
main is just an unevaluated thunk, and executing it is just building up the data structure. I'm trying to apply the same principle here and see why the first main does not terminate. If someone can help me understand this part, or give me pointers to understanding this would be great. Apart from this, why is GHCI not able to recognize this as TCO ? does is not fit the definition?
main = loop
where
loop = do
c <- getChar
case valid c of
Nothing -> return ()
Just b -> print b
print c
loop
> main :: IO ()
> main = loop
> where
> loop = do
> c <- getChar
> case validate c of
> Nothing -> return ()
> Just b -> do
> print b
> loop
Thanks.
Tail-call optimization has nothing to do with this behaviour. The problem is simply that the first code contains an infinite loop while the second doesn't.
Your first code is similar to the imperative (python-like):
def loop():
c = getChar()
if valid c:
do_something()
else:
do_something_else()
print(c)
loop()
While the latter is similar to:
def loop():
c = getChar()
if valid c:
do_something()
else:
do_something_else()
print(c)
loop()
Note how in the latter case the call to loop() is inside the branch else while in the former it's outside and thus is called at every loop invocation.
Also note that return in Haskell does not terminate the function calls. It's just an IO action that has a certain value and no side-effects.
For example:
main = do
c <- return 1
print c
In the above code the return does not prevent the output from print.
This is somewhat related to David's question here. I'm interested in looping over an array of symbols (pointing to objects) and performing an operation on each step of the loop. For example, suppose I want to write a function that looks at a bunch of variables and converts any scalars to one-element arrays.
widget = "a scalar"
dohickey = ["item 1", "item 2"]
gizmo = "another scalar"
theVariables = [:widget, :dohickey, :gizmo]
for thisVariable in theVariables
if !(typeof(eval(thisVariable)) <: Array)
println("Found a scalar")
#Make it a vector here
end
end
Ideally at the end of this we would have the following
widget = ["a scalar"]
dohickey = ["item 1", "item 2"]
gizmo = ["another scalar"]
This is a fairly lame example, but how can this be done? I thought I should be able to use something like
:($thisVariable) = [:($thisVariable)]
but I can't get it to work.
Edit: DSM's solution below works for the case described above, but in my actual usage I want to do this inside a function. If I define
function getsort(; arga="", argb="", argc="")
filterSpecs = [:arga, :argb, :argc]
for ts in filterSpecs
if !(typeof($ts) <: Array)
#nothing here
end
end
end
and then call getsort() it throws
error compiling getsort: error compiling __getsort#31__: syntax: prefix $ in non-quoted expression
I'm clearly missing something about metaprogramming magic.
This is more a followup to #DSM's answer but writing code in comments is hard. A word of caution: eval evaluates in the global scope which can lead to strange things
julia> a = 3
3
julia> function f(a)
eval(:(a = 1))
println(a)
end
f (generic function with 1 method)
julia> f(a)
3
julia> a
1
From the code generation section of the docs, I think all you need is
#eval $thisVariable = [$thisVariable]
For example:
widget = "a scalar"
dohickey = ["item 1", "item 2"]
gizmo = "another scalar"
theVariables = [:widget, :dohickey, :gizmo]
for thisVariable in theVariables
if !(typeof(eval(thisVariable)) <: Array)
println("Found a scalar")
#eval $thisVariable = [$thisVariable]
end
end
which gives me
Found a scalar
Found a scalar
julia> widget
1-element Array{ASCIIString,1}:
"a scalar"
julia> dohickey
2-element Array{ASCIIString,1}:
"item 1"
"item 2"
julia> gizmo
1-element Array{ASCIIString,1}:
"another scalar"
Are you sure you need a macro here? If you're looking to just handle your function inputs you can do something like:
julia> function newDictOfArrays(d)
wrapped=false
for (k,v) in d
if !(typeof(v) <: AbstractArray)
wrapped = true
d[k] = [v]
end
end
(wrapped, d)
end
newDictOfArrays (generic function with 1 method)
julia> function f(; kwargs...)
(wrapped, d) = newDictOfArrays(Dict(kwargs))
if wrapped
return f(;d...)
end
println("continue knowing all keyword args have been wrapped: $kwargs")
end
f (generic function with 1 method)
julia> f(a=1, b=[2])
continue knowing all keyword args have been wrapped: Any[(:a,[1]),(:b,[2])]
julia> f(a=[1], b=[2])
continue knowing all keyword args have been wrapped: Any[(:a,[1]),(:b,[2])]
newDictOfArrays checks all members of a dictionary for values that are not subtypes of AbstractArray, and overrides that item with a wrapped value. In f, if anything was wrapped, it re-calls the same function again with the new dictionary passed as keyword arguments. No macros, eval, etc, although you could consider writing a macro that injects the code into f automatically if need this frequently.