Tracks
/
Crystal
Crystal
/
Exercises
/
Castle Dinner
Castle Dinner

Castle Dinner

Learning Exercise

Introduction

Crystal has a type which is called Nil, it can only have one value: nil. It is used to represent the absence of a value, and is similar to null or None in other languages.

Nil values can be returned from various methods for example String#[]?, which returns nil if the index is out of bounds.

"foo"[10]? # => nil

Crystal has what is known as NULL REFERENCE CHECKS, which means that all types are non-nilable by default. This means that you can not assign nil to a variable unless you explicitly declare it as a Nil type. In turn this means that the compiler will automatically check for null references.

Falsey value

To be able to handle nil values, are there certain approaches that can be taken. nil is a falsey value as well are false. This means that in if statements and other places where a falsey or truthy value is expected it will be treated the same as false.

if nil
  puts "nil is truthy"
else
  puts "nil is falsey"
end

# => nil is falsey

This means that the truthy branch won't be taken if a nilable variable has a value of nil.

foo = "boo"[2]? # It is possible that foo is nil
if foo
  p foo.class # => Char
end

Check for nil

Crystal has a method that can be used to check if a value is nil. It is called nil? and it is available on all objects.

foo = "boo"[2]?
if foo.nil?
  puts "foo is nil"
else
  puts "foo is not nil"
end

This is a bit different when just using the value in an if statement, since in the last examples would both false and nil be treated as false. Here only nil is treated as falsy, since if it was false it wouldn't have been nil thereby it would have been truthy.

Or operator

The easiest way to deal with nil values is by ensuring that the value never becomes nil in the first place. The or operator (||) is often used when dealing with Bools but if understood correctly it can be used to deal with nil values as well. The or operator checks if the first value is truthy, if not the second value is used. This can be used to make if the value is nil it will be falsey and thereby the second value will be used.

"foo"[10]? || "bar" # => "bar"

Instructions

Your majesty is hosting a dinner party in the Kalmar Unions capital Copenhagen. It is the biggest party of the year and all the nobles are invited. But rumors are spreading across the country that there is a plot to poison your majesty.

Her majesty has asked you, the royal poison finder, to find out if any of the food or drinks are poisoned. Your majesty is planning to serve only Mushroom pasties as food, but for drinks, there are a variety of drinks.

1. Check if the food is correct

There is a high chance that the food is poisoned if it is not the food that her majesty ordered. If the food is not the food that her majesty ordered, then it should be tossed out.

Implement the check_food? method, which takes the argument food which holds the name of the food as a String. The method should return the food if the food is "Mushroom pasties", otherwise it should return nil.

CastleDinner.check_food?("Mushroom pasties")
# => "Mushroom pasties"

CastleDinner.check_food?("Bread")
# => nil

2. Check if the drink is poisoned

There is a possibility that the drink is poisoned, but it is a bit more difficult to tell if the drink is poisoned. The drink is poisoned if it does not include the letter i in the name, the casing doesn't matter. The drink should be tossed out if it is poisoned.

Implement the check_drink? method, which takes the argument drink which holds the drink's name as a String. The method should return the drink if it is not poisoned, otherwise it should return nil.

CastleDinner.check_drink?("Apple juice")
# => "Apple juice"

CastleDinner.check_drink?("Tea")
# => nil

3. Replace the drink

Your majesty wouldn't want to make their guests worried about poison in their food. Thereby if the drink is poisoned, it should be replaced with a new drink, specifically Apple juice.

Implement the replace_drink method, which takes the argument drink which holds the name of the drink as a String. The method should return the drink if it is not poisoned, otherwise it should return "Apple juice".

CastleDinner.replace_drink("Orange juice")
# => "Orange juice"

CastleDinner.replace_drink("Tea")
# => "Apple juice"
Edit via GitHub The link opens in a new window or tab
Crystal Exercism

Ready to start Castle Dinner?

Sign up to Exercism to learn and master Crystal with 21 concepts, 126 exercises, and real human mentoring, all for free.