Skip to content

Commit 58a7065

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 6665d4e + d92996f commit 58a7065

1 file changed

Lines changed: 9 additions & 9 deletions

File tree

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ Types let programmers rely on the compiler catch programmer errors, where an ope
1111

1212
For example, you might have a function that returns longitude and latitude for a street address:
1313

14-
```
14+
```scala
1515
def locateAddress(address: String): (Double, Double) = ???
1616
```
1717

1818
This typed interface might catch some errors for you, but it won't stop you from accidentally calling your function on a person's name (`locateAddress(person.name)`). Or maybe more likely, since the results are both `Double`s, it would be pretty easy to get them mixed up (`val (latitude, longitude) = locateAddress(address)`).
1919

2020
With tagged types, the function would take the same values, but its signature might look like:
2121

22-
```
22+
```scala
2323
def locateAddress(address: Address): (Longitude, Latitude) = ???
2424
```
2525

@@ -33,7 +33,7 @@ As a bonus, even if you used converted this function to an anonymous function of
3333

3434
Include the following line in your `build.sbt`:
3535

36-
```
36+
```sbt
3737
libraryDependencies ++= Seq(
3838
"com.acjay" %% "taggy" % "1.0.0"
3939
)
@@ -51,36 +51,36 @@ scalacOptions in (Compile, console) ~= (_ filterNot (_ contains "paradise"))
5151

5252
Import the annotation:
5353

54-
```
54+
```scala
5555
import com.acjay.taggy.tagged
5656
```
5757

5858
Then, declare your tagged type, specifying the underlying type as a string literal:
5959

60-
```
60+
```scala
6161
@tagged type Address = String
6262
@tagged type Longitude = Double
6363
@tagged type Latitude = Double
6464
```
6565

6666
When data enters your system as a string, upgrade it to the tagged type:
6767

68-
```
68+
```scala
6969
val address = Address.fromString("123 Main Street")
7070
val longitude = Longitude.fromDouble(44.12345)
7171
```
7272

7373
In a lot of cases, the compiler will let you pass a tagged type where its underlying type is expected, but not always. When you need to widen back to the underlying type:
7474

75-
```
75+
```scala
7676
val addressAsPlainString = address.untagged // addressAsPlainString: String
7777
```
7878

7979
### Additional notes
8080

8181
- You can often write generic implicits for [de]serialization of tagged types. For example, to do this with Spray-JSON serialization, you might do something like:
8282

83-
```
83+
```scala
8484
import com.acjay.taggy.tag
8585
import com.acjay.taggy.tag.@@
8686
implicit def taggedStringTypeFormat[NewTypeTag](implicit reader: JsonReader[String], writer: JsonWriter[String]): JsonFormat[String @@ NewTypeTag] = new JsonFormat[String @@ NewTypeTag] {
@@ -93,7 +93,7 @@ val addressAsPlainString = address.untagged // addressAsPlainString: String
9393

9494
A fully generic version doesn't seem to work:
9595

96-
```
96+
```scala
9797
// THIS CODE FAILS DUE TO IMPLICIT DIVERGENCE
9898
implicit def taggedTypeFormat[NewTypeTag, UnderlyingType](implicit reader: JsonReader[UnderlyingType], writer: JsonWriter[UnderlyingType]): JsonFormat[UnderlyingType @@ NewTypeTag] = new JsonFormat[UnderlyingType @@ NewTypeTag] {
9999
def read(json: JsValue) = tag[NewTypeTag](reader.read(json))

0 commit comments

Comments
 (0)