As a Scala user, I spend a lot of my time thinking about my types. Making
good use of types is the key to compile time correctness checking, since
compilers are not yet good at checking control flow. For example, consider
the following:

The first method, foo1, is basically a translation to the Java approach
to null checking (if(o != null)) and foo2 is the more idiomatic Scala
approach. As long as you have no mistakes, they do the same thing. The difference
is that the first approach is correctness is achieved with manual control flow, and
the second one makes use of our types for correctness.

then this is a runtime error. Compilers are much better at saving us from type-correctness
mistakes than from control flow mistakes. So then, how can we take better advantage of
this? How can we move as much of our logic into our compile verified types?

Perhaps the most important thing types do for our correctness is not the methods they
provide, but actually the methods they do not provide. The more limitations our types
have, the less possibility we have for bugs.

defsum(xs:List[Int]):Int/*All of the following implmentations would compile!*/defsum(xs:List[Int])=40defsum(xs:List[Int])=xs.foldLeft(0)(_+_)defsum(xs:List[Int])=xs.foldLeft(0)(_+_)-1

Since the type signature doesn't limit our implementation, we can return any
integer, or have a bug that puts our answer off by some integer value. We can improve
this a little bit by telling the method less about the types:

Clearly, if we can limit what the compiler allows us to do to only the correct things,
we'll have fewer bugs. But can this apply to real code we write every day?

Consider something I deal with in telecom software. In the SMS ecosystem, every carrier
is identified by 2 numbers,
a "Mobile Country Code" and a "Mobile Network Code". These
ids just happen to be integers. However, when working with them, it's never valid to
do any of the things computer languages are allowed to do to integers. It makes no sense
to add or decrement an MCC. The MCC 210 has no relationship to 209 to 211. So how can I stop
the compiler from letting me do this? Or worse yet, passing an MCC into a field where an MNC
was required. I can't count the number of times this has happened thanks to lazy copy/paste.
It's embarrassing.

and this is ok. It solves the problem above with passing an MCC where we need an MNC.
But, on the JVM, it incurs a small cost of extra runtime objects. And, it's not nice to
have to wrap numbers in constructors all the time.

What we really want is something like Haskell's newtype keyword, which is like a type
alias at runtime, but like a new type at compile time. It let's us say "these are not the
same thing" at compile time, even if they are the same at runtime.

Luckily, Scala 2.10 added value classes!
Value classes let you wrap a primitive type without changing the runtime underlying representation.
All you need to do is subclass with extends AnyVal. Now,

Give us type safety between different types that both happen to be integer numbers

Have 0-cost of types at runtime; at runtime we have a regular primitive int

Let us write literal numbers and have them converted into the appropriate types

Prevents us from doing unrelated "integer things", like math, to the identifiers

Learning Scala was really a huge shift for me. Although I'd never spent much time
in statically typed languages, it never occurred to me the type system can actually
be a benefit to you, instead of your adversary when trying to make something compile.

To the extent these techniques are even possible in languages like Java, people seem
to avoid using them. In open source Java code, I often see null being abused to
get around type safety, or things being "stringly typed." Java 1.9 might be adding native
support for value types, however.

In any case, whatever language you're in, use the type system to its fullest. It's really
the only way a compiler can prevent your bugs.