The Crystal Programming Language Forum

[Help] adding two numbers

I’m a begginer to programming languages, I studied C++ and Java.

I know Crystal has its codding foundations in Ruby, but I’m not familiar to the Ruby syntax.

My problem is quite simple. I need to get two integers input from the user and then add it to a third variable.

A = gets
B = gets

X = A + B

puts "X = #{X}"

I get this error message:

4 | X = A + B
           ^
Error: undefined method '+' for Nil (compile-time type is (String | Nil))

Can someone help on this?

The reason is that Crystal performs NULL checks at compile time. The compiler is telling you that when you are trying to add 2 values there can be NULL values there (nil in Crystal and Nil is corresponding type).

You are using gets method which can return nil IO - Crystal 1.1.1 (see method return type is String? which is shortcut for writing union type explicitly like String | Nil). That’s why you get this error.

To make sure your code works you need to add explicit checks for case when values can be nil. You can use if/else for that.

Also in Crystal local variable names are lowercase like local_var_name and names starting with capital letters are for constants, classes, etc.

So use something like that:

a = gets
b = gets

if a && b
  x = a + b
else
  x = nil
end

p! x

And here is an example output:

1
2
x # => "12"

You get "12" which is string because gets returns strings and strings can be concatenated with +.

See also how p! x prints both the expression x and it’s value "12". You might use p, p!, pp, and pp! macros for debugging purpose. See for example Top Level Namespace - Crystal 1.1.1)-macro

1 Like

Assuming you are using gets to receive input from a terminal, just do this:

a = gets.to_x
b = gets.to_x
...

where to_x is the numerical type of your input values.

So depending on the number types do: to_i32, to_u32, etc, etc

But to do numerical math you need to convert the strings returned by gets into specific numerical types, because Crystal is a Typed language.

(You don’t need to care, too much, about numerical value types in Ruby.)

1 Like

a = gets.to_x wouldn’t work because gets returns String?. You would have to do gets.not_nil!.to_x.

1 Like

Also something else I want to mention: one way to make gets return nil is by pressing ctrl+D on the terminal while being asked for an input. Another way is to pipe an empty file to the process.

There’s also readline which is equivalent to gets.not_nil! (though I personally don’t like it and I’d like it to be removed from the language)

2 Likes

This isn’t the main issue, but something else to be aware of is that A, B, and X are constants because they begin with capital Latin characters. I’m not sure, but I think that could be an issue for your code.

1 Like

I think I’m not familiar with these concepts yet.

So the behavior of gets is always assumying the input is a String? In other cases will I always have to specify the type like

a = gets.to_i

?

The code that worked for the little exercise was

a = gets.not_nil!.to_i
b = gets.not_nil!.to_i

x = a + b

puts "X = #{x}"

Does the not_nil! works in a similar way to what you said?

Cheking some solutions to this problem in Ruby I saw

a = gets.chomp.to_i

What does the chomp do? When searching for gets in the crystal-lang API I saw there was a parameter chomp .

Yes, the code that worked for me was

a = gets.not_nil!.to_i

Yes, but could also be nil as @asterite pointed out.

not_nil! is mainly used for cases where you can be 100% sure a value won’t be nil and the compiler cannot determine that. It’s usually suggested to not use it everywhere and instead use more robust nil handling logic. Such as one of the forms of if mentioned in if - Crystal or Object - Crystal 1.2.0-dev.

I’m pretty sure it just removes the trailing \n from the string read in from STDIN.

Normally you shouldn’t use not_nil! in your code. It’s an escape hatch for rare occasions.

Try running this program and hot Ctrl + D. You’ll see this runtime exception:

Unhandled exception: Nil assertion failed (NilAssertionError)
  from /usr/local/Cellar/crystal/1.1.1/src/nil.cr:108:5 in 'not_nil!'
  from h.cr:1:5 in '__crystal_main'
  from /usr/local/Cellar/crystal/1.1.1/src/crystal/main.cr:110:5 in 'main_user_code'
  from /usr/local/Cellar/crystal/1.1.1/src/crystal/main.cr:96:7 in 'main'
  from /usr/local/Cellar/crystal/1.1.1/src/crystal/main.cr:119:3 in 'main'

So by using not_nil! you’ve lost compile time guarantees Crystal gives you against nil values.

Try running this and also hit Ctrl + D:

a = gets
b = gets

if a && b
  x = a + b
else
  x = nil
end

p! x

So use if/else to explicitly handle cases when Crystal compiler tells you that there could be nil value and you have’t handled such case in your code:

Error: undefined method '+' for Nil (compile-time type is (String | Nil))

Like already mentioned here: