Introduction to
Lenses in Scala
Introduction to
Lenses in Scala
Shivansh Srivastava
Software Consultant
Knoldus Software LLP
Shivansh Srivastava
Software Consultant
Knoldus Software LLP
AgendaAgenda
● What are Lens?
● Why Lens ?
● Available Implementations.
● Demo.
● What are Lens?
● Why Lens ?
● Available Implementations.
● Demo.
What are LENS ?What are LENS ?
What is Lens ?What is Lens ?
A Lens is an abstraction from functional programming
which helps to deal with a problem of updating complex
immutable nested objects.
Let's start with an example.
case class Turtle(
xcor: Double,
ycor: Double,
heading: Double)
If we want to mutate the value of the heading then.
In the Old Scala Days(2.7):
If we want to mutate the value of the heading then.
In the Old Scala Days(2.7):
case class Turtle(...) {
def right(...): Turtle =
Turtle(xcor,ycor,heading + delta)}
Scala 2.8 comes to the rescue:
case class Turtle(...) {
def right(...): Turtle =
copy(heading = heading + delta)
so far,
so good!
but now...
This is where its needs gets arose.This is where its needs gets arose.
When Nesting plays its partWhen Nesting plays its part
Why Lenses ?Why Lenses ?
Updating mutable
case class Turtle(var ..., ...) {
def forward(dist: Double): Unit = {
position.x += dist * cos(...)
position.y += dist * sin(...)
}
...
Updating (Mutable)
updating
(immutable)
case class Turtle(...) {
def forward(dist: Double): Turtle =
copy(position =
position.copy(
x = position.x +
dist * cos(...),
y = position.y +
dist * sin(...)))
Updating (Immutable)
it gets
worse
case class Turtle(...) {
def forward(dist: Double): Turtle =
this.copy(position =
this.position.copy(
x = this.position.x +
dist * cos(this....),
y = this.position.y +
dist * sin(this....)))
OO Style:
FP style
case class Turtle(...) // no methods
def forward(turtle: Turtle,
dist: Double): Turtle =
turtle.copy(position =
turtle.position.copy(
x = turtle.position.x +
dist * cos(turtle....),
y = turtle.position.y +
dist * sin(turtle....)))
FP Style:
worse
still
n levels deep
// imperative
a.b.c.d.e += 1
// functional
a.copy(
b = a.b.copy(
c = a.b.c.copy(
d = a.b.c.d.copy(
e = a.b.c.d.e +
1))))
What if we go N levels deep:
case class Program(
...
breeds: ListMap[String, Breed] =
ListMap(),
linkBreeds: ListMap[String, Breed] =
ListMap(),
...
)
Production Code:
Production Code:
// if we had lenses this wouldn't get so repetitious
// - ST 7/15/12
if (isLinkBreed)
program.copy(linkBreeds =
orderPreservingUpdate(
program.linkBreeds,
program.linkBreeds(breedName).copy(
owns = newOwns)))
else
program.copy(breeds =
orderPreservingUpdate(
program.breeds,
program.breeds(breedName).copy(
owns = newOwns)))
https://github.com/NetLogo/NetLogo/blob/15700ba6bcab813c5be8b49b8fa00c2204883b08/
headless/src/main/org/nlogo/compiler/StructureParser.scala#L266-L276
We Can Fix it:
omit needless repetition!
avoid nested copy()
The need of the lens arises when there is too much nesting.
If we want to increase userRating in this model then we
will have to write such a code:
If we want to increase userRating in this model then we
will have to write such a code:
And we have to write the code below to confirm all of the
addresses in BillInfo.
And we have to write the code below to confirm all of the
addresses in BillInfo.
If we want to increase userRating in this model then we
will have to write such a code:
If we want to increase userRating in this model then we
will have to write such a code:
If we increase a level of nesting in our structures then we
will considerably increase amount of a code like this. In
such cases lens give a cleaner way to make changes in
nested structures.
Using <<quicklens>> we can do it much simpler:
If we increase a level of nesting in our structures then we
will considerably increase amount of a code like this. In
such cases lens give a cleaner way to make changes in
nested structures.
Using <<quicklens>> we can do it much simpler:
Available ImplementationsAvailable Implementations
There are several implementations in scala:
 scalaz.Lens
 Quicklens
 Sauron
There are several implementations in scala:
 scalaz.Lens
 Quicklens
 Sauron
Available Implementations
If we want to use scalaz.Lens at first we should
define lens:
If we want to use scalaz.Lens at first we should
define lens:
scalaz.Lens:
The first type parameter is needed to set in which class(MainClass)
we will change value and the second type parameter defines the
class(FieldClass) of the field which we will change with the lens.
We should also send two functions to lensu(...) method. The first
function defines how to change MainClass using a new value. The
second function is used to get value of the field which we want to
change.
Quicklens:
Use of scalaz.Lens is quite difficult.It is quite hard and we will
reduce amount of the code only if we have very complex
nesting and implement enough lens to compose them.
Quicklens has support of chain modifications which can be
helpful if you want to change several fields at the same time
It is also possible to create reusable lens as well as
in scalaz.Lens
It is also possible to create reusable lens as well as
in scalaz.Lens
QuickLens:
QuickLens:
And the lens composition is also possible:And the lens composition is also possible:
Sauron:Sauron:
It is said on the main page of Sauron repo it has been inspired
by quicklens but it has much simpler implementation and less
number of features. And also has additional dependency on
"org.scalamacros" % "paradise" % "2.1.0-M5"
Sauron:Sauron:
The example below shows how to define lens for
changing different objects:
Sauron:Sauron:
The example below shows hot to define lens for changing
different objects:
Results:
➔ scalaz.Lens - If you already have scalaz in a project
and you are not bothered to write some code in order
to define lens
➔ Quicklens - Easy to use and powerful enough to deal
with the described problem
➔ Sauron - Very similar to Quicklens and has a less size
but also has less functionality
Refrences:Refrences:
 www.koff.io
 Slides by Seth Tisue in ScalaDays 2013
 https://github.com/pathikrit/sauron
 https://github.com/adamw/quicklens
Thanks..!!Thanks..!!

Scala lens: An introduction

  • 1.
    Introduction to Lenses inScala Introduction to Lenses in Scala Shivansh Srivastava Software Consultant Knoldus Software LLP Shivansh Srivastava Software Consultant Knoldus Software LLP
  • 2.
    AgendaAgenda ● What areLens? ● Why Lens ? ● Available Implementations. ● Demo. ● What are Lens? ● Why Lens ? ● Available Implementations. ● Demo.
  • 3.
    What are LENS?What are LENS ?
  • 4.
    What is Lens?What is Lens ? A Lens is an abstraction from functional programming which helps to deal with a problem of updating complex immutable nested objects. Let's start with an example. case class Turtle( xcor: Double, ycor: Double, heading: Double)
  • 5.
    If we wantto mutate the value of the heading then. In the Old Scala Days(2.7): If we want to mutate the value of the heading then. In the Old Scala Days(2.7): case class Turtle(...) { def right(...): Turtle = Turtle(xcor,ycor,heading + delta)} Scala 2.8 comes to the rescue: case class Turtle(...) { def right(...): Turtle = copy(heading = heading + delta)
  • 6.
  • 7.
    This is whereits needs gets arose.This is where its needs gets arose. When Nesting plays its partWhen Nesting plays its part
  • 8.
  • 9.
    Updating mutable case classTurtle(var ..., ...) { def forward(dist: Double): Unit = { position.x += dist * cos(...) position.y += dist * sin(...) } ... Updating (Mutable)
  • 10.
    updating (immutable) case class Turtle(...){ def forward(dist: Double): Turtle = copy(position = position.copy( x = position.x + dist * cos(...), y = position.y + dist * sin(...))) Updating (Immutable)
  • 11.
  • 12.
    case class Turtle(...){ def forward(dist: Double): Turtle = this.copy(position = this.position.copy( x = this.position.x + dist * cos(this....), y = this.position.y + dist * sin(this....))) OO Style:
  • 13.
    FP style case classTurtle(...) // no methods def forward(turtle: Turtle, dist: Double): Turtle = turtle.copy(position = turtle.position.copy( x = turtle.position.x + dist * cos(turtle....), y = turtle.position.y + dist * sin(turtle....))) FP Style:
  • 14.
  • 15.
    n levels deep //imperative a.b.c.d.e += 1 // functional a.copy( b = a.b.copy( c = a.b.c.copy( d = a.b.c.d.copy( e = a.b.c.d.e + 1)))) What if we go N levels deep:
  • 16.
    case class Program( ... breeds:ListMap[String, Breed] = ListMap(), linkBreeds: ListMap[String, Breed] = ListMap(), ... ) Production Code:
  • 17.
    Production Code: // ifwe had lenses this wouldn't get so repetitious // - ST 7/15/12 if (isLinkBreed) program.copy(linkBreeds = orderPreservingUpdate( program.linkBreeds, program.linkBreeds(breedName).copy( owns = newOwns))) else program.copy(breeds = orderPreservingUpdate( program.breeds, program.breeds(breedName).copy( owns = newOwns))) https://github.com/NetLogo/NetLogo/blob/15700ba6bcab813c5be8b49b8fa00c2204883b08/ headless/src/main/org/nlogo/compiler/StructureParser.scala#L266-L276
  • 18.
    We Can Fixit: omit needless repetition! avoid nested copy()
  • 19.
    The need ofthe lens arises when there is too much nesting.
  • 20.
    If we wantto increase userRating in this model then we will have to write such a code: If we want to increase userRating in this model then we will have to write such a code: And we have to write the code below to confirm all of the addresses in BillInfo. And we have to write the code below to confirm all of the addresses in BillInfo. If we want to increase userRating in this model then we will have to write such a code: If we want to increase userRating in this model then we will have to write such a code:
  • 21.
    If we increasea level of nesting in our structures then we will considerably increase amount of a code like this. In such cases lens give a cleaner way to make changes in nested structures. Using <<quicklens>> we can do it much simpler: If we increase a level of nesting in our structures then we will considerably increase amount of a code like this. In such cases lens give a cleaner way to make changes in nested structures. Using <<quicklens>> we can do it much simpler:
  • 22.
  • 23.
    There are severalimplementations in scala:  scalaz.Lens  Quicklens  Sauron There are several implementations in scala:  scalaz.Lens  Quicklens  Sauron Available Implementations
  • 24.
    If we wantto use scalaz.Lens at first we should define lens: If we want to use scalaz.Lens at first we should define lens: scalaz.Lens: The first type parameter is needed to set in which class(MainClass) we will change value and the second type parameter defines the class(FieldClass) of the field which we will change with the lens. We should also send two functions to lensu(...) method. The first function defines how to change MainClass using a new value. The second function is used to get value of the field which we want to change.
  • 25.
    Quicklens: Use of scalaz.Lensis quite difficult.It is quite hard and we will reduce amount of the code only if we have very complex nesting and implement enough lens to compose them. Quicklens has support of chain modifications which can be helpful if you want to change several fields at the same time
  • 26.
    It is alsopossible to create reusable lens as well as in scalaz.Lens It is also possible to create reusable lens as well as in scalaz.Lens QuickLens:
  • 27.
    QuickLens: And the lenscomposition is also possible:And the lens composition is also possible:
  • 28.
    Sauron:Sauron: It is saidon the main page of Sauron repo it has been inspired by quicklens but it has much simpler implementation and less number of features. And also has additional dependency on "org.scalamacros" % "paradise" % "2.1.0-M5"
  • 29.
    Sauron:Sauron: The example belowshows how to define lens for changing different objects:
  • 30.
    Sauron:Sauron: The example belowshows hot to define lens for changing different objects:
  • 31.
    Results: ➔ scalaz.Lens -If you already have scalaz in a project and you are not bothered to write some code in order to define lens ➔ Quicklens - Easy to use and powerful enough to deal with the described problem ➔ Sauron - Very similar to Quicklens and has a less size but also has less functionality
  • 32.
    Refrences:Refrences:  www.koff.io  Slidesby Seth Tisue in ScalaDays 2013  https://github.com/pathikrit/sauron  https://github.com/adamw/quicklens
  • 33.

Editor's Notes

  • #22 many web application want to increase application throughput, responsivenesswhere one task can make progress without waiting for all others to completewhere more than one task can make progress at same time.Concurrent program can be executed on single core machine via time slicYou may execute concurrent program in parallelOverall you play with threads