fork download
  1. import scala.language.{higherKinds, implicitConversions}
  2.  
  3. trait Counter {
  4. def value: Int
  5. }
  6.  
  7. class MutableCounter(var value: Int) extends Counter
  8.  
  9. case class ImmutableCounter(value: Int) extends Counter
  10.  
  11. trait CounterOps[C <: Counter] {
  12. def count(): C
  13. }
  14.  
  15. class MutableCounterOps(counter: MutableCounter)
  16. extends CounterOps[MutableCounter] {
  17. override def count(): MutableCounter = {
  18. counter.value += 1
  19. counter
  20. }
  21. }
  22.  
  23. object MutableCounterOps {
  24. implicit def counterToOps(counter: MutableCounter): MutableCounterOps =
  25. new MutableCounterOps(counter)
  26. }
  27.  
  28. class ImmutableCounterOps(counter: ImmutableCounter)
  29. extends CounterOps[ImmutableCounter] {
  30. override def count(): ImmutableCounter =
  31. ImmutableCounter(counter.value + 1)
  32. }
  33.  
  34. object ImmutableCounterOps {
  35. implicit def counterToOps(counter: ImmutableCounter): ImmutableCounterOps =
  36. new ImmutableCounterOps(counter)
  37. }
  38.  
  39. class EchoingCounterOps[C <: Counter](
  40. baseCounterOpsProvider: C => CounterOps[C],
  41. counter: C)
  42. extends CounterOps[C] {
  43. override def count(): C = {
  44. println("Counting from: " + counter.value)
  45. baseCounterOpsProvider(counter).count()
  46. }
  47. }
  48.  
  49. object EchoingCounterOps {
  50. trait EchoingCounterOpsProvider[C <: Counter] {
  51. implicit def counterToOps(counter: C): CounterOps[C]
  52. }
  53.  
  54. def compose[C <: Counter, CO <: CounterOps[C]](
  55. baseCounterOpsProvider: C => CO): EchoingCounterOpsProvider[C] = {
  56. new EchoingCounterOpsProvider[C] {
  57. override implicit def counterToOps(counter: C): CounterOps[C] =
  58. new EchoingCounterOps(baseCounterOpsProvider, counter)
  59. }
  60. }
  61. }
  62.  
  63. object Main {
  64. def main(args: Array[String]): Unit = {
  65. println("Echoing mutable...")
  66. echoingMutable()
  67. println("Echoing immutable...")
  68. echoingImmutable()
  69. }
  70.  
  71. def echoingMutable(): Unit = {
  72. val composed = EchoingCounterOps.compose(MutableCounterOps.counterToOps)
  73. import composed.counterToOps
  74.  
  75. val counter = new MutableCounter(3)
  76. println("New value: " + counter.count().count().count().value)
  77. println("Retained value: " + counter.value)
  78. }
  79.  
  80. def echoingImmutable(): Unit = {
  81. val composed = EchoingCounterOps.compose(ImmutableCounterOps.counterToOps)
  82. import composed.counterToOps
  83.  
  84. val counter = ImmutableCounter(3)
  85. println("New value: " + counter.count().count().count().value)
  86. println("Retained value: " + counter.value)
  87. }
  88. }
  89.  
Success #stdin #stdout 0.33s 4382720KB
stdin
Standard input is empty
stdout
Echoing mutable...
Counting from: 3
Counting from: 4
Counting from: 5
New value: 6
Retained value: 6
Echoing immutable...
Counting from: 3
Counting from: 4
Counting from: 5
New value: 6
Retained value: 3