
Wrapper classes
In Scala, we can create our own universe, apart from the native methods provided, we can add our own implementations, which we call Rich Wrapper classes. This is possible because of Implicit Conversions. First, we'll list out some Wrappers available already:

To see how it happens, let's see an example:
scala> val x = 10
x: Int = 10
scala> x.isValidByte
res1: Boolean = true
The preceding expression tries to check if the value of x can be converted into a Byte, and suffices range of a Byte, and finds it to be true:
scala> val x = 260
x: Int = 260
scala> x.isValidByte
res2: Boolean = false
scala> val x = 127
x: Int = 127
scala> x.isValidByte
res3: Boolean = true
As you know, range for a Byte is -128 to 127. If you try to assign it to a value that's out of range of a Byte and expect it to behave like a Byte, it won't work. Thus, the result for the preceding expression is false.
Apart from this isValidByte, there are a number of utility methods present in the class RichByte wrapper class.
These wrappers methods look like they're natively defined for the types existing. One of the examples is a wrapper around a String that is StringOps. A String in Scala is nothing more than an instance of java.lang.String, so it's clear that all methods implemented for java.lang.String are applicable here as well. For example, the charAt method does pretty good here:
scala> val x = "I am a String"
x: String = I am a String
scala> x.charAt(5)
res13: Char = a
Now let's try some methods from StringOps:
scala> x.capitalize
res14: String = I am a String
scala> x.toUpperCase
res15: String = I AM A STRING
scala> x.toLowerCase
res16: String = i am a string
The three methods capitalize, toUpperCase, and toLowerCase are defined in the StringOps class and not in String classes, but still it works the same way as calling a native method for a String type. There are more of these methods that work as a utility method for Strings. This is because of the power of Implicit Conversions. We'll learn how Implicits work in Scala in later chapters.
One of the ways to create a Range class out of Int types can be achieved using a method to. We call these rich methods. It's really simple to use them, and based on the purpose they solve, we can also name them:
scala> val rangeOfNumbers = 1 to 199
rangeOfNumbers: scala.collection.immutable.Range.Inclusive = Range 1 to 199
scala> val rangeOfNumbersUntil = 1 until 199
rangeOfNumbersUntil: scala.collection.immutable.Range = Range 1 until 199
scala> rangeOfNumbers contains 1
res17: Boolean = true
scala> rangeOfNumbersUntil contains 1
res18: Boolean = true
scala> rangeOfNumbersUntil contains 199
res19: Boolean = false
scala> rangeOfNumbers contains 199
res20: Boolean = true
The preceding are few examples of methods from the Range class, which provide rich methods for Int to create a Range with. The Range can contain values inclusive of those. It's built with, and can also exclude, those values. Methods for building these are to and until. The first includes both values we use to build a Range; the latter includes only the beginning value. We've tried all these. As you can see, rangeOfNumbersUntil does not contain 199. We can also create a Range with some step difference:
scala> 1 to 10 by 2 foreach println
The following is the result:
1
3
5
7
9
This is pretty simple; pretty and simple. Especially with the syntax, we are able to write concisely because of Implicit Conversions and Type Inference happening at the backend. Scala Compiler is taking care of all those parts, leaving us with the simple job of writing code in a beautiful way. Another way of utilizing conciseness while writing a String is by using String Interpolators.