15 Volts
15 Volts

Reputation: 2077

Error: undefined local variable or method 'var' for top-level

I am new to the crystal programming language.

Whenever I run this code:

var = ARGV.find { |x| x.split(".").size == 4 } || "0.0.0.0"

ARGV.delete(var)
Addr = var.split(".").map { |x| x.to_i { 0 } }.join(".")
p Addr

With crystal, I get an Error:

Showing last frame. Use --error-trace for full trace.

In q.cr:4:8

 4 | Addr = var.split(".").map { |x| x.to_i { 0 } }.join(".")
            ^--
Error: undefined local variable or method 'var' for top-level

But whenever I omit the last line p Addr, or replace var with Var, the code seems to work fine.

Crystal Version:

Crystal 0.31.1 (2019-10-21)

LLVM: 9.0.0
Default target: x86_64-pc-linux-gnu

What's the problem in my code?

Upvotes: 1

Views: 653

Answers (1)

Jonne Haß
Jonne Haß

Reputation: 4857

This is a little gotcha that we hopefully will get better error messages for in the future.

So the first piece to this puzzle is to understand that var is a local variable because it starts with a lowercase letter and Addr is a constant because it starts with an upper case letter.

For reasons constant initializers, so the code after the = sign in an constant assignment, are run lazily the first time the constant is accessed. Because of this they exist in their own scope and cannot reference the local variable defined in the top level scope.

So there's three ways out of this for your example. First making Addr a local variable too by calling it addr. Second promoting var to a constant by calling it Var. Or third putting your entire code into the constant initializer:

Addr = begin
  ip = ARGV.find { |arg| arg.count('.') == 3 } || "0.0.0.0"
  ARGV.delete(ip)
  ip.split('.').map { |part| part.to_i { 0 } }.join('.')
end

Which of the three is best depends largely on taste and the structure of your program.

Upvotes: 5

Related Questions