I can make "literals" of type Int64 and even Uint8 in Julia:
julia> typeof(8)
Int64
julia> typeof(0x08)
Uint8
But I haven't been able to find out how to make a literal of type Int8. I have tried a few different things:
julia> 8::Int8
ERROR: type: typeassert: expected Int8, got Int64
julia> 0x08::Int8
ERROR: type: typeassert: expected Int8, got Uint8
julia> convert(Int8, 8)
8
julia> typeof(ans)
Int8
So the application of the convert function worked, but that's a somewhat wordy expression. I was wondering if there was something a little more concise, perhaps like Rust's 8i8.
I am using Julia 0.3.3, but answers for Julia 0.4.x would be fine too.
More convenient than convert(Int8, 8) is Int8(8) respective int8(8) on earlier versions. The reason that few number literal notations like 8i8 exist is that it conflicts with multiplication by juxtaposition.
julia> i8=8
8
julia> 3i8
24
Related
I am having some issues understanding the concept of parametric constructors in Julia. I am looking at the standard example in the Julia docs:
struct Point{T<:Real}
x::T
y::T
end
To my understanding, this means I can generate a Point-datatype with an input that is subtype of Real, i.e., AbstractFloat, AbstractIrrational, ..., Integer, Rational, ..., StatsBase.TestStat.
However, both of the examples below result in errors:
Point(Integer(12))
Point(Rational(12))
Why does the above fail given that both integer and rational are subtypes of real?
The type parameter goes inside the curly braces in the constructor call, just like it does in the struct definition:
julia> Point{Integer}(12, 12)
Point{Integer}(12, 12)
julia> Point{Rational}(12, 10//3)
Point{Rational}(12//1, 10//3)
The arguments supplied are the values for the fields of the struct i.e. x and y. If the arguments are already of the type you want, you can leave out explicitly specifying the type parameter:
julia> Point(12, 6)
Point{Int64}(12, 6)
julia> Point(12.0, 6.0)
Point{Float64}(12.0, 6.0)
julia> Point(12, 6.0) #no automatic type promotion happens though
ERROR: MethodError: no method matching Point(::Int64, ::Float64)
Closest candidates are:
Point(::T, ::T) where T<:Real at REPL[1]:2
Stacktrace:
[1] top-level scope
# REPL[9]:1
julia> Point{Float64}(12, 6.0) #unless you explicitly specify the type
Point{Float64}(12.0, 6.0)
I have a module, say, called Constants,
module Constants
const zero = 0.0 :: Float64
const czero = 0.0 + 0.0im :: Complex
end
I know like I can define like zero as Float64. But How do I define a "Complex" and "Float64" variable such as czero? Currently I use Complex, but I want to be more specific. If I use ComplexF64
const czero = 0.0 + 0.0im :: ComplexF64
it gives me an error,
ERROR: LoadError: TypeError: in typeassert, expected Complex{Float64}, got a value of type Complex{Bool}
So what concrete type of Complex should I use?
I give each variable a concrete type is because I heard that if the code looks like Fortran it can run like Fortran, because I define the type first so Julia do not have to convert the type which can be very slow.
This question is not quite clear, but perhpas what you need is zero:
julia> zero(ComplexF64)
0.0 + 0.0im
julia> dump(zero(ComplexF64))
ComplexF64
re: Float64 0.0
im: Float64 0.0
Other options include using the constructor such as ComplexF64(0.0) or ComplexF64(0.0,0.0) or using the complex(0.0) function. These are all type stable.
::
With the ::-operator type annotations are attached to expressions and variables in programs. See the manual section on Type Declarations.
Outside of declarations :: is used to assert that expressions and variables in programs have a given type.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> (1+2)::AbstractFloat
ERROR: TypeError: typeassert: expected AbstractFloat, got a value of type Int64
julia> (1+2)::Int
3
With this in mind, obviously julia considers the declaration invalid because of operator precedence, so just put parentheses if you want to do the declaration this way
const czero = (0.0 + 0.0im) ::ComplexF64
I also second the opinion above: if you're just trying to declare zeros then what you need is zero
I'm just experimenting with Julia and found that it gives incorrect value when run:
Input:
println(1000^6)
println(1000^7)
println(1000^8)
println(1000^9)
Output:
1000000000000000000
3875820019684212736
2003764205206896640
-6930898827444486144
Is this an issue or am I doing it wrong?
As explained the problem is due to integer overflow. Maximum value you can store in an Int64 can be obtained thanks to
julia> typemax(Int64)
9223372036854775807
However, 1000^9 is bigger, as you can see with:
julia> BigInt(1000)^9
1000000000000000000000000000
I wrote a fairly complex macro that manipulates an array, but it didn't work. I get the same error message even after replacing my macro with something ridiculously simple:
macro len(arr::Array)
length(arr)
end
#len [1 2 3]
The error message I get is:
ERROR: LoadError: MethodError: no method matching #len(::Expr)
Why is Julia insisting on interpreting my input as an expression? I'm completely new to Julia, and there is obviously something I don't understand about either macros or the type system. Can someone please explain?
EDIT: Time to explain what my original macro was for. I want to take a table as input and use it to define variables in the local scope. The entries in the first column define individual variable names and the other columns define variable contents. Since a function can't do this, I need a macro. I have a working macro that takes a long (triple-quoted) string as input, but now I want it to take an array as input instead.
After this explanation, maybe I should add another subquestion: why does my other macro accept the appropriate input (it is defined as macro foo(text::String)) whereas the array version doesn't?
User Chris Rackauckas answered this on irc in discussion with me:
#len $a
macros are on expressions, not on the values, so
this sounds like something you'd want a function for
(if it's really needed at all).
I'm not sure this would work there anyway.
This isn't what macros are for..
it's for converting expressions into other expressions, mostly.
If you're trying to use macros on values, then you want a function
(you may be able to #eval or something to make this work here, but you'll be going through great lengths to make a macro act like a function)
..as a function:
julia> function len(x)
length(x)
end
len (generic function with 1 method)
julia> len(a)
3
julia> a
1x3 Array{Int64,2}:
1 2 3
To answer my own question: this is how that "ridiculously simple" macro should have been written.
macro len(expr)
:(length($expr))
end
This operates on an expression, not an array (thank you Chris Rackauckas and Isaiah for pointing that out). I was misled by my own experiments, since a similar macro for strings happens to work:
# MISLEADING CODE, DON'T USE THIS!
macro lenstr(str::String)
length(str)
end
Apparently Julia allows string macros, but this is an exception to the general rule that macros operate on expressions. To illustrate how arguments appear to the macro:
macro dump(arg)
dump(arg)
end
julia> #dump "foo bar"
String "foo bar"
julia> #dump [1,2,3]
Expr
head: Symbol vect
args: Array{Any}((3,))
1: Int64 1
2: Int64 2
3: Int64 3
typ: Any
julia> #dump [1 2 3]
Expr
head: Symbol hcat
args: Array{Any}((3,))
1: Int64 1
2: Int64 2
3: Int64 3
typ: Any
Note how [1,2,3] and [1 2 3] are seen by the macro as expressions, not arrays. This was the source of my error. By applying lessons learned here, my more complex macro that creates variables in a local scope from an array now works. Thank you all!
I encountered a problem which I've solved, but why the solution works doesnt make sense to me
I had a function similar to this one
function testB(a::Array{AbstractString})
println(a)
end
running it like so gave me
testB(convert(Array{UTF8String},["a","b"]))
ERROR: MethodError: `testB` has no method matching
testB(::Array{UTF8String,1})
Note that Im not manually converting to UTF8 in reality, its for demonstration, in reality I have an AbstractString array, but when I fetch elements from it, they become UFT8
My solution reads in short
function testA{T <: AbstractString}(a::Array{T})
println(a)
end
running this method gives
testA(convert(Array{UTF8String},["a","b"]))
UTF8String["a","b"]
Can anyone tell me why testA works but testB doesnt?
Also, is there a name for this {T <: SomeDataType} notation?
While UTF8String is a subtype of AbstractString, Array{UTF8String} is not a subtype of Array{AbstractString} (no covariance). Hence your testB does not work. (But testB(convert(Array{AbstractString},["a","b"])) should work.)
Rationale for why it has to be like this: a function f(x::Vector{AbstractString}) could e.g. push! a new FooString into x (assuming FooString is a subtype of AbstractString). Now if x was in fact a Vector{UTF8String}, that would fail.