More Safety Through Types

Crystal provides more than performance. The Crystal compiler also provides the benefits of static type-checking, preventing lots of runtime errors. The following snippet, which again is both Ruby and Crystal syntax, shows how this works. It calls a method add, which in turn calls + on several values:

 def​ ​add​(x, y)
  x + y
 end
 
 puts add(2, 3) ​# => 5
 # () can be left out in method calls
 puts add(1.0, 3.14) ​# => 4.14
 puts add(​"Hello "​, ​"Crystal"​) ​# => "Hello Crystal"
 # + concatenates two strings

You know that + is defined for integers, floats, and strings, but what if you try:

 puts add(42, ​" times"​)

To run this in Ruby, use $ ruby error1.cr. The program puts out the values 5, 4.14, and “Hello Crystal,” and then reports a runtime error crashing the program:

 '+': String can't be coerced into Fixnum (TypeError).

Ruby interprets code when it is run, and methods are looked up at runtime. Ruby won’t find the problem until it’s well into the program.

To run the same code in Crystal, use $ crystal error1.cr. This time there is no output. Crystal compiles the complete program in a separate step before execution starts. Because Crystal detects an error during that process, it stops at compile time and the program doesn’t run:

 Error in error1.cr:8: instantiating 'add(Int32, String)'
 add(42, " times")
  ^~~
 in error1.cr:2: no overload matches 'Int32#+' with type String

Crystal has no method to add a string to an integer. The compiler knows this and halts. The code never comes close to execution.

Now take a look at this situation, again in code with syntax that fits both Crystal and Ruby:

 str = ​"Crystal"
 ix = str.​index​(​'z'​)
 puts str[ix]

This looks up the location ix of the character ‘z’ in the string str, which contains “Crystal.” What if the character doesn’t occur in the string as is the case here? In both Ruby and Crystal, ix would be nil to indicate that nothing is found.

Ruby throws an error if the character isn’t found: $ ruby error2.cr

 error2.cr:3:in `[]': no implicit conversion from nil to integer (TypeError)
 from error2.cr:3:in `main'

This happens at runtime, hopefully while you’re testing and not while your customers are using the program.

Crystal, however, gives an error during compilation:

$ crystal error2.cr

 Error in error2.cr:3: no overload matches 'String#[]' with type (Int32 | Nil)

The error contains a lot more information, but this is the key line. The compiler catches the possible error, even before you’re in a testing phase, let alone in production. The error message also pinpoints the exact problem, somewhat better than Ruby does: the [] method of String won’t work with a nil argument. In other words: looking up item at position ix of str fails when ix is nil.

You can remedy this situation as in Ruby by testing ix as follows:

 if​ ix
  puts str[ix]
 end

An if in Crystal accepts true and all other values, except false and nil (and null pointers). So in the if-branch Crystal knows that ix can’t be nil, and there’s no compile error any longer.

Crystal also lets you avoid compilation errors while still supporting methods that accept a variety of different types. Moving beyond Ruby syntax, Crystal lets you create different methods that have the same name but use different argument types, called overloading.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.5.15