How to insert variables that might be `nothing` into strings in Julia? - julia

I am trying to make a dynamic string in Julia by inserting the value of a variable into the string. Everything worked fine until today when the value returned nothing leaving me with an error.
How do I include a nothing in a string? At least without having to go through the hassle of some if n == nothing; n = "None" thing for every variable I want to insert into a string.
function charge_summary(charges_df)
if size(charges_df)[1] > 0
n_charges = size(charges_df)[1]
total_charges = round(abs(sum(charges_df[:amount])), digits=2)
avg_charges = round(abs(mean(charges_df[:amount])), digits=2)
most_frequent_vender = first(sort(by(charges_df, :transaction_description, nrow), :x1, rev=true))[:transaction_description]
sms_text = """You have $n_charges new transactions, totaling \$$total_charges.
Your average expenditure is \$$avg_charges.
Your most frequented vender is $most_frequent_vender.
"""
return sms_text
else
return nothing
end
end
sms_msg = charge_summary(charges_df)
Returns:
ArgumentError: `nothing` should not be printed; use `show`, `repr`, or custom output instead.
string at io.jl:156 [inlined]
charge_summary(::DataFrame) at get-summary.jl:18
top-level scope at none:0
include_string(::Module, ::String, ::String, ::Int64) at eval.jl:30
(::getfield(Atom, Symbol("##105#109")){String,Int64,String})() at eval.jl:91
withpath(::getfield(Atom, Symbol("##105#109")){String,Int64,String}, ::String) at utils.jl:30
withpath at eval.jl:46 [inlined]
#104 at eval.jl:90 [inlined]
hideprompt(::getfield(Atom, Symbol("##104#108")){String,Int64,String}) at repl.jl:76
macro expansion at eval.jl:89 [inlined]
(::getfield(Atom, Symbol("##103#107")))(::Dict{String,Any}) at eval.jl:84
handlemsg(::Dict{String,Any}, ::Dict{String,Any}) at comm.jl:168
(::getfield(Atom, Symbol("##14#17")){Array{Any,1}})() at task.jl:259

Unfortunately you have to explicitly handle nothing. For example like this:
Your most frequented vender is $(something(most_frequent_vender, "None")).
The reason for this is that it is not clear how you would want nothing to be converted to a string, so you have to provide this value (in your case you wanted "None").
A shorter version would be:
Your most frequented vender is $(repr(most_frequent_vender)).
but then nothing is printed as "nothing".

Define Base.string(x::Nothing) method:
➜ ~ julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.0.3 (2018-12-20)
_/ |\__'_|_|_|\__'_| | android-termux/900b8607fb* (fork: 1550 commits, 315 days)
|__/ |
julia> Base.string(x::Nothing) = repr(x) # or just return the string "None", that's up to you.
julia> "$(nothing)"
"nothing"
julia>
Julia 1.3 update
Allow nothing to be printed #32148

Related

TypeError: non-boolean (Num) used in boolean context with symbolic Julia, How to fix?

Opened an issue as suggested. https://github.com/JuliaSymbolics/Symbolics.jl/issues/718
I wanted to translate this
To Julia. So Installed symbolics, defined x but get an error. The following is the code
>julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.7.3 (2022-05-06)
_/ |\__'_|_|_|\__'_| |
|__/ |
julia> using Symbolics
julia> #variables x
1-element Vector{Num}:
x
julia> sqrt(-im+x)
ERROR: TypeError: non-boolean (Num) used in boolean context
Stacktrace:
[1] sqrt(z::Complex{Num})
# Base ./complex.jl:501
[2] top-level scope
# REPL[3]:1
julia>
Noticed that im+x works. But sqrt(im+x) gives the error.
What is the problem and is there a workaround?

How to translate (-Csch[x]^2)^(1/2) to Julia symbolic? ERROR: DomainError with -csch

Fyi, Just in case this is a bug in Julia symbolic, added new issue at https://github.com/JuliaSymbolics/Symbolics.jl/issues/719
I am trying to translate the following. In Mathematica
In Maple:
To Julia symbolics. Where csch is hyperbolic cosecant function and x is syms. But Julia gives an error on (-csch(x)^2)^(1//2) but no error on (csch(x)^2)^(1//2)
Here is the code
>julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.7.3 (2022-05-06)
_/ |\__'_|_|_|\__'_| |
|__/ |
julia> using Symbolics
julia> #syms x
(x,)
julia> (-csch(x)^2)^(1//2)
ERROR: DomainError with -1.0:
Exponentiation yielding a complex result requires a complex argument.
Replace x^y with (x+0im)^y, Complex(x)^y, or similar.
Stacktrace:
[1] throw_exp_domainerror(x::Float64)
# Base.Math ./math.jl:37
[2] ^
# ./math.jl:909 [inlined]
[3] ^
# ./promotion.jl:413 [inlined]
[4] ^
# ./rational.jl:479 [inlined]
[5] unstable_pow
# ~/.julia/packages/SymbolicUtils/qulQp/src/types.jl:801 [inlined]
[6] ^(a::SymbolicUtils.Mul{Number, Int64, Dict{Any, Number}, Nothing}, b::Rational{Int64})
# SymbolicUtils ~/.julia/packages/SymbolicUtils/qulQp/src/types.jl:1047
[7] top-level scope
# REPL[3]:1
I noticed however that this works
julia> sqrt(-csch(x)^2)
sqrt(-(csch(x)^2))
But in my case, the exponents are not always 1/2 and so this is not a workaround for me. For example, I could have (-csch(x)^2)^(1//3) and so on. But it is strange that it accepts sqrt and not ^(1//2) in this example.
What exactly is the issue and is there a workaround?

Julia RemoteChanel example gives UndefVarError

I tried to run the example from https://docs.julialang.org/en/v1/manual/parallel-computing/#Channels-and-RemoteChannels-1
Just copy-pasted commands to my julia console. I am using version 1.0.0
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.0.0 (2018-08-08)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> nprocs()
5
julia> const results = RemoteChannel(()->Channel{Tuple}(32));
julia> const jobs = RemoteChannel(()->Channel{Int}(32));
julia> #everywhere function do_work(jobs, results) # define work function everywhere
while true
job_id = take!(jobs)
exec_time = rand()
sleep(exec_time) # simulates elapsed time doing actual work
put!(results, (job_id, exec_time, myid()))
end
end
julia> function make_jobs(n)
for i in 1:n
put!(jobs, i)
end
end;
julia> n = 12
12
julia> #async make_jobs(n);
julia> for p in workers() # start tasks on the workers to process requests in parallel
remote_do(do_work, p, jobs, results)
end
julia> #elapsed while n > 0 # print out results
job_id, exec_time, where = take!(results)
println("$job_id finished in $(round(exec_time; digits=2)) seconds on worker $where")
n = n - 1
end
It gave the following error:
4 finished in 0.46 seconds on worker 4
ERROR: UndefVarError: n not defined
Stacktrace:
[1] macro expansion at ./REPL[9]:4 [inlined]
[2] top-level scope at ./util.jl:213 [inlined]
[3] top-level scope at ./none:0
Why it crashed on worker 4? I assumed the while loop should run only on master.
The problem is that line:
n = n - 1
should be
global n = n - 1
This is unrelated to workers but new scope rules in Julia 1.0 (see https://docs.julialang.org/en/latest/manual/variables-and-scoping/#Local-Scope-1).
The example in the manual should be fixed.
Edit: the example is fixed on master https://docs.julialang.org/en/v1.1-dev/manual/parallel-computing/, but was not backported.

How to compose external command in julia using concatenation of different variables?

i'd like to do something like :
arg= " -l "
cmd = "ls $arg "
run(cmd)
but i can find no simple solution to do that :
$ julia
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: https://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.6.0 (2017-06-19 13:05 UTC)
_/ |\__'_|_|_|\__'_| | Official http://julialang.org/ release
|__/ | x86_64-pc-linux-gnu
julia> arg=" -l "
" -l "
julia> cmd=`ls $arg`
`ls ' -l '`
julia> run(cmd)
ls: cannot access -l : No such file or directory
ERROR: failed process: Process(`ls ' -l '`, ProcessExited(2)) [2]
Stacktrace:
[1] pipeline_error(::Base.Process) at ./process.jl:682
[2] run(::Cmd) at ./process.jl:651
julia> cmd="ls $arg"
"ls -l "
julia> run(`$cmd`)
ERROR: could not spawn `'ls -l '`: no such file or directory (ENOENT)
Stacktrace:
[1] _jl_spawn(::String, ::Array{String,1}, ::Ptr{Void}, ::Base.Process, ::RawFD, ::RawFD, ::RawFD) at ./process.jl:360
[2] #373 at ./process.jl:512 [inlined]
[3] setup_stdio(::Base.##373#374{Cmd}, ::Tuple{RawFD,RawFD,RawFD}) at ./process.jl:499
[4] #spawn#372(::Nullable{Base.ProcessChain}, ::Function, ::Cmd, ::Tuple{RawFD,RawFD,RawFD}) at ./process.jl:511
[5] run(::Cmd) at ./process.jl:650
should i split the resulting string to separate each part (cause there is no shell doing the job ?)
by the way, how to get the exit status of the command ?
thanks a lot
Try:
arg = "-l"
cmd = `ls $arg`
run(cmd)
And read running external programs
to understand more.

#spawn and #async behavior in the REPL

I've read through the documentation for #async and #spawn, but this isn't shown:
function f1(j)
for i=1:j
println(i*j)
end
end
function f2(j)
for i=1:j
#spawn println(i*j)
end
end
When run the second value is always skipped with both #async and #spawn
julia> f1(5)
5
10
15
20
25
julia> f2(5)
5
julia>
15
20
25
It doesn't seem to have an impact on the output of the data into an array (...or does it?), and doing #sync f2(5) reverts the behavior. Mostly just wondering why this happens and why the second value?
Edit:
It acts like this on two systems:
julia> versioninfo()
Julia Version 0.4.0-dev+4850
Commit c260ea9* (2015-05-15 15:14 UTC)
Platform Info:
System: Darwin (x86_64-apple-darwin13.4.0)
CPU: Intel(R) Core(TM) i5-2415M CPU # 2.30GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Sandybridge)
LAPACK: libopenblas
LIBM: libopenlibm
LLVM: libLLVM-3.3
julia> versioninfo()
Julia Version 0.4.0-dev+4888
Commit ca2ca31* (2015-05-18 15:20 UTC)
Platform Info:
System: Linux (x86_64-linux-gnu)
CPU: AMD FX(tm)-8120 Eight-Core Processor
WORD_SIZE: 64
BLAS: libopenblas (NO_LAPACK NO_LAPACKE DYNAMIC_ARCH NO_AFFINITY Bulldozer)
LAPACK: liblapack.so.3
LIBM: libopenlibm
LLVM: libLLVM-3.3
I can also reproduce the problem if I use the 0.4 nightly:
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "help()" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.4.0-dev+5032 (2015-05-27 06:04 UTC)
_/ |\__'_|_|_|\__'_| | Commit bae38c2* (0 days old master)
|__/ | x86_64-apple-darwin13.4.0
julia> function f2(j)
for i=1:j
#spawn println(i*j)
end
end
f2 (generic function with 1 method)
julia> f2(5)
5
julia>
15
20
25
Version 0.3 tends to choose a different timing which does not have destructive competition for drawing to the terminal:
julia> f2(5)
510152025
julia>
(Here, each println worked out as a buffer print and a newline print interleaved with the other tasks.)
The reason 0.4 nightly's output looks like it is not complete is just the combination of how timing works out with how terminals handle newlines, moving to a dumb terminal allows the 10 to be seen:
$ TERM="dumb" ./julia-4
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: http://docs.julialang.org
_ _ _| |_ __ _ | Type "help()" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.4.0-dev+5032 (2015-05-27 06:04 UTC)
_/ |\__'_|_|_|\__'_| | Commit bae38c2* (0 days old master)
|__/ | x86_64-apple-darwin13.4.0
WARNING: Terminal not fully functional
julia> function f2(j)
for i=1:j
#spawn println(i*j)
end
end
f2 (generic function with 1 method)
julia> f2(5)
5
julia> 10
15
20
25
In general, you can count on any processing you request via #spawn or #async to be carried out, you just can't count on how the competition for any shared resources works out. This case of a shared terminal is one example. Any shared data structure built by async/spawned processes could be built by the computations running in any order and interleaving their modifications, etc.
An example where the main task handles organizing the output of the other tasks could look like this:
function f3(j)
x = Any[#spawn i*j for i=1:j]
for i in x
println(fetch(i))
end
end
Naturally, this would only perform well enough to make up for the cost of moving the data around if the i*j were replaced with a function with high CPU usage and/or reasons to wait for I/O that were more significant than the bottleneck of writing to the single output file or TTY.

Resources