Are there subtile differences between one and multiline if expressions in Julia? - julia

I am using Julia 1.1.1 and discovered something interesting yesterday.
Minimal example below
Consider the following code:
julia> if ((true)) true else false end
true
Works as intended
However, when attempting to do the following:
julia> function foo()
true
end
foo (generic function with 1 method)
julia> if ((foo())) (true,false) else (false,true) end
ERROR: syntax: space before "(" not allowed in "foo() ("
julia>
However, when writing the expression in the standard way it seems to work
julia> if ((foo()))
(true, false)
else
false
end
(true, false)
julia>
From my understanding from the following post Does Julia have a ternary conditional operator? I should be allowed to write if expressions in much the same way as ternaries and I usually can. However, for this case the ternary operator seems to be working as intended but not the if expression
julia> ((foo())) ? (true,false) : (false,true)
(true, false)
Does it exists a subtile difference between the two?
As noted in the comments by crstnbr the following syntax is allowed:
if ((foo())) true,false else false,true end

This does not seem to have anything to do with the if block per se. It is simply a syntax error.
Effectively, julia prohibits the syntax myfun (args) when calling a function (i.e. no space is allowed between the function name and the parentheses).
Since the output of a function, e.g., in this case foo(), may be another function, the same rule must apply to returned arguments. You wrapping your foo() function in infinite parentheses does nothing to resolve this, since the output of that expression is still asked to be evaluated via wrong syntax.
For example, note that:
julia> foo()()
ERROR: MethodError: objects of type Bool are not callable
Stacktrace:
[1] top-level scope at none:0
whereas
julia> foo() ()
ERROR: syntax: space before "(" not allowed in "foo() ("
Furthermore, as I mentioned in my comment above, regardless of the above, I personally would consider such terse if blocks very bad style, as well as a bad idea, as you have yourself just figured out. If you don't want to split into lines, it's is still a good idea, and much more readable, to use a semicolon at the end of the appropriate statements to show clear separation (both to yourself reading the code, and to the interpreter).
i.e.
if true; true, false; else; false, true; end
if foo(); true, false; else; false, true; end

Related

Plotting an float array in julia

I have the following code
using Plots
function test()::nothing
A::Array{Float64,1} = rand(Float64,100)
plot(A)
end
Which I run in julia like this
julia> include("main.jl")
test (generic function with 1 method)
julia> test()
ERROR: MethodError: First argument to `convert` must be a Type, got nothing
Stacktrace:
[1] test() at /path/to/main.jl:85
[2] top-level scope at REPL[2]:1
Why do I get the error First argument to convert must be a Type, got nothing ?
Well, this problem is related to the fact that you were using nothing in annotation, but correct type is Nothing (note capital N). nothing is an object, Nothing is a type of this object.
So you should use something like
function test()::Nothing
A::Array{Float64,1} = rand(Float64, 100)
display(plot(A))
nothing
end
Note, that I had to add nothing as return value and explicit display to show actual plot.
But, to be honest, main problem is not the Nothing, but overspecialization. Type annotations in functions do not speed up calculations, you should use them only when they are really needed, for example in multiple dispatch.
Idiomatic code looks like this
function test()
A = rand(100)
plot(A)
end
Note, that I removed all extra annotations and unnecessary Float64 in rand, since it is default value.

Why is a Julia function name (without arguments) silently ignored?

I have a script that defines a function, and later intended to call the function but forgot to add the parentheses, like this:
function myfunc()
println("inside myfunc")
end
myfunc # This line is silently ignored. The function isn't invoked and there's no error message.
After a while I did figure out that I was missing the parentheses, but since Julia didn't give me an error, I'm wondering what that line is actually doing? I'm assuming that it must be doing something with the myfunc statement, but I don't know Julia well enough to understand what is happening.
I tried --depwarn=yes but don't see a julia command line switch to increase the warning level or verbosity. Please let me know if one exists.
For background context, the reason this came up is that I'm trying to translate a Bash script to Julia, and there are numerous locations where an argument-less function is defined and then invoked, and in Bash you don't need parentheses after the function name to invoke it.
The script is being run from command line (julia stub.jl) and I'm using Julia 1.0.3 on macOS.
It doesn't silently ignore the function. Calling myfunc in an interactive session will show you what happens: the call returns the function object to the console, and thus call's the show method for Function, showing how many methods are currently defined for that function in your workspace.
julia> function myfunc()
println("inside myfunc")
end
myfunc (generic function with 1 method)
julia> myfunc
myfunc (generic function with 1 method)
Since you're calling this in a script, show is never called, and thus you don't see any result. But it doesn't error, because the syntax is valid.
Thanks to DNF for the helpful comment on it being in a script.
It does nothing.
As in c, an expression has a value: in c the expression _ a=1+1; _ has the value _ 2 _ In c, this just fell out of the parser: they wanted to be able to evaluate expressions like _ a==b _
In Julia, it's the result of designing a language where the code you write is handled as a data object of the language. In Julia, the expression "a=1+1" has the value "a=1+1".
In c, the fact that
a=1+1;
is an acceptable line of code means that, accidentally,
a;
is also an acceptable line of code. The same is true in Julia: the compiler expects to see a data value there: any data value you put may be acceptable: even for example the data value that represents the calculated value returned by a function:
myfunc()
or the value that represents the function object itself:
myfunc
As in c, the fact that data values are everywhere in your code just indicates that the syntax allows data values everywhere in your code and that the compiler does nothing with data values that are everywhere in your code.

Tell if number is odd or even with SML

This is the second SML program I have been working on. These functions are mutually recursive. If I call odd(1) I should get true and even(1) I should get false. These functions should work for all positive integers. However, when I run this program:
fun
odd (n) = if n=0 then false else even (n-1);
and
even (n) = if n=0 then true else odd (n-1);
I get:
[opening test.sml]
test.sml:2.35-2.39 Error: unbound variable or constructor: even
val it = () : unit
How can I fix this?
The problem is the semicolon (;) in the middle. Semicolons are allowed (optionally) at the end of a complete declaration, but right before and is not the end of a declaration!
So the compiler is blowing up on the invalid declaration fun odd (n) = if n=0 then false else even (n-1) that refers to undeclared even. If it were to proceed, it would next blow up on the illegal occurrence of and at the start of a declaration.
Note that there are only two situations where a semicolon is meaningful:
the notation (...A... ; ...B... ; ...C...) means "evaluate ...A..., ...B..., and ...C..., and return the result of ...C....
likewise the notation let ... in ...A... ; ...B... ; ...C... end, where the parentheses are optional because the in ... end does an adequate job bracketing their contents.
if you're using the interactive REPL (read-evaluate-print loop), a semicolon at the end of a top-level declaration means "OK, now actually go ahead and elaborate/evaluate/etc. everything so far".
Idiomatic Standard ML doesn't really use semicolons outside of the above situations; but it's OK to do so, as long as you don't start thinking in terms of procedural languages and expecting the semicolons to "terminate statements", or anything like that. There's obviously a relationship between the use of ; in Standard ML and the use of ; in languages such as C and its syntactic descendants, but it's not a direct one.
I'm sure there's a didactic point in making these functions recursive, but here's some shorter ones:
fun even x = x mod 2 = 0
val odd = not o even

How to define a function inside a function depending on variable values

I'm writing a function that I would find easier to write and read if it could define another function differently depending on input or runtime values of variables (and then use that function). The following illustrates the idea (even if defining a function inside a function is of no advantage in this simple example):
julia> function f(option::Bool)
if option
g() = println("option true")
g()
else
g() = println("option false")
g()
end
end;
WARNING: Method definition g() in module Main at REPL[1]:3 overwritten at REPL[1]:6.
julia> f(true)
option false
julia> f(false)
ERROR: UndefVarError: g not defined
in f(::Bool) at .\REPL[1]:7
Using the full function ... end syntax for g does not help either.
The question is: am I doing something wrong to get that warning and that unintended behavior, or Julia does not allow this for a reason? And if it can be done, how?
N.B. For my present need, I can just define two different functions, g1 and g2, and it seems to work; but what if there were many cases of g for just one task concept? I thought that a function, being a first-class object, could be manipulated freely: assigned to a variable, defined in a way or another depending on conditions, overwritten, etc.
P.S. I know I can compose a String and then parse-eval it, but that's an ugly solution.
You want to use anonymous functions. This is a known issue (this other issue also shows your problem).
function f(option::Bool)
if option
g = () -> println("option true")
else
g = () -> println("option false")
end
g
end
In v0.5 there's no performance difference between anonymous and generic functions, so there's no reason to not use anonymous functions. Note that there's also a sytnax for extended anonymous functions:
f = function (x)
x
end
and you can add dispatches via call overloading:
(T::typeof(f))(x,y) = x+y
so there's no reason to not use an anonymous function here.

Confusion with ' operator and bracketing where (v')*v becomes Ac_mul_B despite overloading

I am playing around with the idea of CoVectors in Julia and am getting some behaviour I didn't expect from the parser/compiler. I have defined a new CoVector type that is the ctranspose of any vector, and is just a simple decoration:
type CoVector{T<:AbstractVector}
v::T
end
They can be created (and uncreated) with ' using ctranspose:
import Base.ctranspose
function CoVector(T::DataType,d::Integer=0)
return CoVector(Array(T,d))
end
function Base.ctranspose(cv::CoVector)
return cv.v
end
function Base.ctranspose(v::AbstractVector)
return CoVector(v)
end
function Base.ctranspose(v::Vector) # this is already specialized in Base
return CoVector(v)
end
Next I want to define a simple dot product
function *(x::CoVector,y::AbstractVector)
return dot(x.v,y)
end
Which can work fine for:
v = [1,2,3]
cv = v'
cv*v
returns 14, and cv is a CoVector. But if I do
(v') * v
I get something different! In this case it is a single element array containing 14. How come parenthesis doesn't work how I expect?
In the end we see the expression gets expanded to Ac_mul_B which defaults to [dot(A,B)] and it seems that this interpretation is defined at the "operator" level.
Is this expected behaviour? Can Julia completely ignore my bracketing and change the expression as it wants? In Julia I like that I can override things in Base but is it also possible to make self-consistent changes to how operators are applied? I see the expression doesn't have head call but Symbol call... does this change in Julia 0.4? (I read somewhere that call is becoming more universal).
I guess I can fix the problem by redefining Ac_mul_B but I was very surprised that it was called at all, given my above definitions.

Resources