Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward type declaration

Tags:

types

julia

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.

like image 611
Vincent Avatar asked Oct 01 '15 07:10

Vincent


People also ask

What is meant by forward declaration?

In computer programming, a forward declaration is a declaration of an identifier (denoting an entity such as a type, a variable, a constant, or a function) for which the programmer has not yet given a complete definition.

What can be forward declared?

The main rule is that you can only forward-declare classes whose memory layout (and thus member functions and data members) do not need to be known in the file you forward-declare it. This would rule out base classes and anything but classes used via references and pointers. Almost.

Where do you put forward declaration?

Generally you would include forward declarations in a header file and then include that header file in the same way that iostream is included.

What is forward declaration of struct?

A struct (without a typedef) often needs to (or should) be with the keyword struct when used. struct A; // forward declaration void function( struct A *a ); // using the 'incomplete' type only as pointer. If you typedef your struct you can leave out the struct keyword.


Video Answer


2 Answers

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>
like image 73
HarmonicaMuse Avatar answered Sep 23 '22 17:09

HarmonicaMuse


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?

like image 26
Toivo Henningsson Avatar answered Sep 20 '22 17:09

Toivo Henningsson