Forward type declaration
You can do variable declaration but not in the global scope; these are the constructs in Julia that introduce a new scope:
Certain constructs in the language introduce scope blocks, which are regions of code that are eligible to be the scope of some set of variables. The scope of a variable cannot be an arbitrary set of source lines; instead, it will always line up with one of these blocks. The constructs introducing such blocks are:
- function bodies (either syntax)
- while loops
- for loops
- try blocks
- catch blocks
- finally blocks
- let blocks
- type blocks.
Notably missing from this list are begin blocks and if blocks, which do not introduce new scope blocks.
You can optionaly use type declarations:
julia> x
ERROR: UndefVarError: x not defined
julia> x::Int
ERROR: UndefVarError: x not defined
julia> begin x end # still in global scope
ERROR: UndefVarError: x not defined
julia> begin x::Int end
ERROR: UndefVarError: x not defined
julia> let x end # local scope
julia> let x; x end
ERROR: UndefVarError: x not defined
Notice that Julia will try to convert the value to the specified type:
julia> let
x::Int # declare variables
y::Float64 = 7 # converts (if possible)
x = y # converts (if possible)
x, y
end
(7, 7.0)
julia> function foo(x, y)
x::Int
y::Float64
z # Any
# there must be assignment for conversion to happen
x, y = x, y
z = 5im
x, y, z
end
foo (generic function with 1 method)
julia> foo(3.0, 7)
(3,7.0,0 + 5im)
Edited example:
Define types/ immutables.
julia> type Foo{T<:Number}
x::T
end
julia> type Bar
x
end
julia> immutable Baz
a
b
c
end
Define conversion methods.
julia> import Base.convert
julia> convert{T<:Number}(::Type{Foo{T}}, x::Number) = Foo(T(x))
convert (generic function with 535 methods)
julia> convert(::Type{Bar}, x) = Bar(x)
convert (generic function with 536 methods)
julia> convert(::Type{Baz}, xs::NTuple{3}) = Baz(xs...)
convert (generic function with 537 methods)
So you can do something like this:
julia> let
# decalre variables:
a::Foo{Int}
b::Foo{Float64}
c::Bar
d::Baz
e::Int
# assign values:
e = 42
a = e
b = e
c = string(e)
d = 'a', e, "test"
[a, b, c, d]
end
4-element Array{Any,1}:
Foo{Int64}(42)
Foo{Float64}(42.0)
Bar("42")
Baz('a',42,"test")
julia>
It seems to me that what you want to do is to create an instance of a type without specifying the contents, and then fill it in later. This is possible to do by creating a constructor that leaves some fields uninitialized:
type Foo
a
# inner constructor that leaves all fields uninitialized
Foo() = new()
end
a = Foo()
b = Foo()
a.a = 5.5
b.a = 4.5
By giving fewer arguments to new
in the inner constructor than the type had fields, the last ones become uninitialized. It is an error to read an uninitialized field before it has been assigned a value.
Is this what you were after?
It is not necessary to pre-declare variables in Julia, since the type is just defined by usage.
If you want to restrict to certain types then you can do that:
type MyType
a::Int
end
(Note that names of types have an initial capital by convention.)
b = MyType(1)
c = MyType(2)
d = MyType(3.5) # error