<commit_before>---
layout: tutorial
title: "Generic module"
section: tutorial
sort: 21
---
While kantan.csv goes out of its way to provide [default instance](default_instances.html) for as many types as it can,
some are made problematic by my strict rule against runtime reflection. Fortunately, [shapeless](http://shapeless.io)
provides _compile time_ reflection, which makes it possible for the `generic` module to automatically derive instances
for more common types and patterns.

The `generic` module can be used by adding the following dependency to your `build.sbt`:

```scala
libraryDependencies += "com.nrinaudo" %% "kantan.csv-generic" % "0.1.9"
```

Let's first declare the imports we'll need in the rest of this tutorial:

```tut:silent
import kantan.csv.ops._     // Provides CSV specific syntax.
import kantan.csv.generic._ // Provides automatic instance derivation.
```

The rest of this post will be a simple list of supported types.

## `CellEncoder`s and `CellDecoder`s

### Case objects

While not the most obviously useful instance, case objects automatically have a [`CellDecoder`] and [`CellEncoder`]
instance, working from and to the empty string.

Here's a case object example:

```tut:silent
case object Foo
```

This can be encoded and decoded without any specific declaration: 

```tut
val decoded = ",,\n,,".unsafeReadCsv[List, List[Foo.type]](',', false)

decoded.asCsv(',')
```

While this might not seem terribly useful, its purpose will become clearer when dealing with sum types. 


### Case classes of arity 1

All case classes of arity 1 have [`CellDecoder`] and [`CellEncoder`] instances, provided the type of their single field
also does.

Let's declare a (fairly useless) case class (we'll be making a more useful one in the next section):

```tut:silent
case class Wrapper[A](a: A)
```

We can directly encode from and decode to instances of `Wrapper`:

```tut
val decoded = "1, 2, 3\n4, 5, 6".unsafeReadCsv[List, List[Wrapper[Int]]](',', false)

decoded.asCsv(',')
```

### Sum types

We can also get free [`CellDecoder`] and [`CellEncoder`] instances for sum types where all alternatives have a
[`CellDecoder`] and [`CellEncoder`]. For example:

```tut:silent
sealed abstract class Maybe[+A]
case class Just[A](value: A) extends Maybe[A]
case object Nothing extends Maybe[Nothing]
```

`Just` is a unary case class, so it has a [`CellCodec`] instance if its type argument has one. `Nothing` is a case
object, so it automatically has [`CellCodec`]. This allows us to write:

```tut
val decoded = "1,, 3\n4, , 6".unsafeReadCsv[List, List[Maybe[Wrapper[Int]]]](',', false)

decoded.asCsv(',')
```

Here's another common example, to show that sum types where both alternatives hold values are supported:

```tut:silent
sealed abstract class Xor[+A, +B]
case class Left[A](value: A) extends Xor[A, Nothing]
case class Right[B](value: B) extends Xor[Nothing, B]
```

Encoding and decoding work just as well as before:

```tut
val decoded = "1,true\nfalse,2".unsafeReadCsv[List, List[Xor[Int, Boolean]]](',', false)

decoded.asCsv(',')
```

## Rows

### Case classes

All case classes have [`RowEncoder`] and [`RowDecoder`] instances, provided all their fields also do.
 
Take, for example, a custom [`Tuple2`] implementation (using an actual [`Tuple2`] might not be very convincing, as
it's supported by kantan.csv without needing the `generic` module):

```tut:silent
case class CustomTuple2[A, B](a: A, b: B)
```

We can encode from and decode to that type for free:

```tut
val decoded = "1,\n2,false".unsafeReadCsv[List, CustomTuple2[Int, Maybe[Boolean]]](',', false)<commit_msg>Add a mention of macro paradise for shapeless on scala 2.10.x<commit_after>---
layout: tutorial
title: "Generic module"
section: tutorial
sort: 21
---
While kantan.csv goes out of its way to provide [default instance](default_instances.html) for as many types as it can,
some are made problematic by my strict rule against runtime reflection. Fortunately, [shapeless](http://shapeless.io)
provides _compile time_ reflection, which makes it possible for the `generic` module to automatically derive instances
for more common types and patterns.

The `generic` module can be used by adding the following dependency to your `build.sbt`:

```scala
libraryDependencies += "com.nrinaudo" %% "kantan.csv-generic" % "0.1.9"
```

If you're using Scala 2.10.x, you should also add the macro paradise plugin to your build:

```scala
libraryDependencies += compilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
```

Let's first declare the imports we'll need in the rest of this tutorial:

```tut:silent
import kantan.csv.ops._     // Provides CSV specific syntax.
import kantan.csv.generic._ // Provides automatic instance derivation.
```

The rest of this post will be a simple list of supported types.

## `CellEncoder`s and `CellDecoder`s

### Case objects

While not the most obviously useful instance, case objects automatically have a [`CellDecoder`] and [`CellEncoder`]
instance, working from and to the empty string.

Here's a case object example:

```tut:silent
case object Foo
```

This can be encoded and decoded without any specific declaration:

```tut
val decoded = ",,\n,,".unsafeReadCsv[List, List[Foo.type]](',', false)

decoded.asCsv(',')
```

While this might not seem terribly useful, its purpose will become clearer when dealing with sum types.


### Case classes of arity 1

All case classes of arity 1 have [`CellDecoder`] and [`CellEncoder`] instances, provided the type of their single field
also does.

Let's declare a (fairly useless) case class (we'll be making a more useful one in the next section):

```tut:silent
case class Wrapper[A](a: A)
```

We can directly encode from and decode to instances of `Wrapper`:

```tut
val decoded = "1, 2, 3\n4, 5, 6".unsafeReadCsv[List, List[Wrapper[Int]]](',', false)

decoded.asCsv(',')
```

### Sum types

We can also get free [`CellDecoder`] and [`CellEncoder`] instances for sum types where all alternatives have a
[`CellDecoder`] and [`CellEncoder`]. For example:

```tut:silent
sealed abstract class Maybe[+A]
case class Just[A](value: A) extends Maybe[A]
case object Nothing extends Maybe[Nothing]
```

`Just` is a unary case class, so it has a [`CellCodec`] instance if its type argument has one. `Nothing` is a case
object, so it automatically has [`CellCodec`]. This allows us to write:

```tut
val decoded = "1,, 3\n4, , 6".unsafeReadCsv[List, List[Maybe[Wrapper[Int]]]](',', false)

decoded.asCsv(',')
```

Here's another common example, to show that sum types where both alternatives hold values are supported:

```tut:silent
sealed abstract class Xor[+A, +B]
case class Left[A](value: A) extends Xor[A, Nothing]
case class Right[B](value: B) extends Xor[Nothing, B]
```

Encoding and decoding work just as well as before:

```tut
val decoded = "1,true\nfalse,2".unsafeReadCsv[List, List[Xor[Int, Boolean]]](',', false)

decoded.asCsv(',')
```

## Rows

### Case classes

All case classes have [`RowEncoder`] and [`RowDecoder`] instances, provided all their fields also do.

Take, for example, a custom [`Tuple2`] implementation (using an actual [`Tuple2`] might not be very convincing, as
it's supported by kantan.csv without needing the `generic` module):

```tut:silent
case class CustomTuple2[A, B](a: A, b: B)
```

We can encode from and decode to that type for free:

```tut
val decoded = "1,\n2,false".unsafeReadCsv[List, CustomTuple2[Int, Maybe[Boolean]]](',', false)
{'fraction_non_alphanumeric': 0.12454945935122147, 'fraction_numerical': 0.007876118008276598, 'mean_word_length': 5.0565885206143895, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1439712', 'n_tokens_mistral': 2420, 'n_tokens_neox': 2273, 'n_words': 964}