Variables in Julia change their type while being constructed

Viewed 43

I am brand new in Julia programming, and am facing a baffling situation, which I simply can't understand. So, this is what I want to do: I have two structs: Shoe and Person, where Person contains a Shoe

This is how the code looks:

struct Shoe
  size  :: Int64
  brand :: String
end

struct Person
  age  :: Int64
  shoe :: Shoe

  function Person(a::Int64, s::Shoe)
    age  = a
    shoe = s
  end

  function Person()
    age  = 33
    shoe = Shoe(17,"Nike")
  end
end

ian = Person(17, Shoe(32,"Puma"))
tom = Person()

println(typeof(ian))
println(typeof(tom))

To my utter surprise, ian and tom, which I try to define as persons, turn out to be shoes. Any idea what am I doing wrong?

1 Answers

function Person, being a constructor for the struct Person, should return an instance of struct Person, but because its last line is shoe = Shoe(17,"Nike") (and because assignment is an expression that evaluates to whatever shoe becomes), it ends up returning that Shoe.

Constructors should call the built-in new constructor:

struct Person
  age  :: Int64
  shoe :: Shoe

  # This function is redundant since
  # it does exactly the same thing as the `new` constructor
  function Person(a::Int64, s::Shoe)
    age  = a
    shoe = s

    new(age, shoe)
  end

  function Person()
    age  = 33
    shoe = Shoe(17,"Nike")

    new(age, shoe)
  end
end

AFAIK, you don't need to use constructors unless they're doing input validation. You do need a constructor to ensure that it's impossible to construct a Person with negative age, for example, because Int64 can be negative. (You could ensure that age >= 0 by using UInt64, too. But then you'd have to write 17 in hexadecimal (0x11) all the time, which is kind of annoying)

I'd write it like this:

struct Person
  age  :: Int64
  shoe :: Shoe

  function Person(age::Int64, shoe::Shoe)
    @assert age >= 0

    new(age, shoe)
  end
end

# Put other constructors outside
Person() = Person(33, Shoe(17, "Nike"))

Example:

julia> Person(-1, Shoe(0, "Hello"))
ERROR: AssertionError: age >= 0
Stacktrace:
 [1] Person(age::Int64, shoe::Shoe)
   @ Main ./REPL[3]:6
 [2] top-level scope
   @ REPL[5]:1

julia> Person()
Person(33, Shoe(17, "Nike"))
Related