Scala Collection API for C# Developers
The .NET Framework has offered a Collection API that is used extensively across all libraries and applications written in C# or any other CRL languages. Developers use it all the time without thinking much about it. Everyone coming from .NET knows what the IEnumerable interface represents and how it is used along with the foreach construct. On the other hand, people coming from the Scala world should have the same knowledge about the Scala Collection API. However, it is, sometimes, hard for new people coming from C# to map the .NET Collection API to the Scala Collection API.
IEnumerable<T>
For the sake of this conversation, we are going to use the generic version of the different components of the framework. The non-generic ones represent the same and we will skip them for this time. IEnumerable and IEnumerable<T> are used interchangeably, yet referring solely to IEnumerable<T>.
In C#, an IEnumerable is something we can enumerate. It is also the root of all enumerable types in .NET.
The IEnumerable interface is shown next.
public interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator()
}
The only method defined within IEnumerable<T> is GetEnumerator() which returns an enumerator that iterates through the collection.
We can use IEnumerable<T> in two ways. We could use the foreach construct or by requesting elements using the IEnumerator<T>. Let’s see an example.
IEnumerable<T> someEnumerable = getAnEnumerable(...);foreach(T item in someEnumerable)
{
... // do something with item
}
or
IEnumerator<T> someEnumerator = getAnEnumerable(...).GetEnumerator();while (someEnumerator.MoveNext())
{
T item = someEnumerator.Current;
... // do something with item
}
The foreach construct is only calling the methods in the IEnumerator<T> making our lives easier. We can implement our own IEnumerator<T> or we can avoid this patterns by using yield return, where the compiler generates the corresponding enumerator.
A very simple IEnumerable can be implemented in the following way:
class MyCollection : IEnumerable<Int>
{
public IEnumerator<Int> GetEnumerator()
{
for (int i = 0; i < 100; i++)
{
yield return i;
}
}
}
Scala Traversable
Traversable is the trait at the top of the hierarchy in the Scala Collection API. Traversable and IEnumerable represent the same, at least conceptually.
The Traversable definition is quite different from the one shown before, but we are going to focus on its only abstract operation, foreach.
def foreach[U](f: Elem => U)
Yes, the foreach method is within the trail, instead of being a language construct. This method takes a function to be applied on each element of the collection. Let’s see an example.
val someIntegers = 1 to 100someIntegers.foreach(item => println(item))
someIntegers.foreach { item =>
... //do something with item
}
Note the different ways to invoke foreach. We can use () or {}. Scala lets us do this when calling curried functions, it comes very handy in some cases.
Scala Iterable
Iterable is closer to what we have seen in IEnumerable<T>. It defines an abstract method iterator
abstract def iterator: Iterator[A]
that matches the GetEnumerator in the .NET Framework.
A .NET IEnumerable<T> can be seen as Scala Iterable combined with the Scala Traversable so we can foreach on it.
In the same way we implemented an IEnumerable we can implement an Iterable.
class MyCollection extends Iterable[Int] {
def iterator: Iterator[Int] = 1.to(100).iterator
}
In both cases (C# seen before and Scala) we could choose to write our own Enumerator / Iterator and their implementation will look very similar.
Going Down the Tree
At this point, we have two very similar trees in both languages. Going down the tree from IEnumerable / Iterable things fork in different paths, yet high level functionalities of respective classes are basically the same.
In .NET, we can find ICollection<T>, from here IDictionary<TKey, TValue> and IList<T>, then the concrete implementation of these interfaces.
In Scala, there are Map[A, B], Seq[A], and Set[A]. If we take a close look to these interface, we will discover that their offer similar functionalities. Concrete implementation of all these interfaces can be very particular in each language, but they all share common roots.
It might look that the Scala Collection API has more functionalities built in, but the majority of them are implemented as extension methods in the System.Linq namespace in C#, again, they APIs are very equivalent to each other.
Endings
Learning something new takes time and dedication, especially when it is something as much as different as C# and Scala. Scala has a lot to offer, and the Collection API is a good place to start at. It does not matter what kind of application you are writing, the Collection API will be present.
I hope this post helps you to look at the Scala Collection API in the same way you look at System.Collection namespace, so you could be more productive in you functional journal in the Scala world.