Vincent
Vincent

Reputation: 1371

Forward type declaration

I was wondering if it is possible in julia to assign a custom or existing type to a variable without calling it's constructor.

Something similar to a forward declaration of a class in c++.

Here is an example of what I intend to achieve:

type foo
    a
end

#custom type
a = foo
b = foo

#julia type, force c to be of type Int
c = Int    


a.a = 5.5
b.a = 4.5

c = 6

Edit To clarify my question:

In C++ or Fortran it is common coding practice to declare a variable at some point for later usage.

I don't recall the correct Fortran syntax but in C++ you would write something like:

class foo;
class bar;
int a;

class foo{
private:
    bar myBar;

public:
    foo(int a){ myBar( a ); }  
}    

class bar{ 
public: 
    bar(int a){ 
        std::cout << a << std::endl;
    } 
}

a = 3;
foo( a );

The advantage of this code structure is that it allows you to define objects / types / variables before you use them.

Upvotes: 8

Views: 2974

Answers (3)

HarmonicaMuse
HarmonicaMuse

Reputation: 7893

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>

Upvotes: 8

David P. Sanders
David P. Sanders

Reputation: 5325

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

Upvotes: 2

Toivo Henningsson
Toivo Henningsson

Reputation: 2709

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?

Upvotes: 3

Related Questions