3

I have one class in Scala with four parameters 2 of them is variable and I wanted to use the Ref data type in Zio to control the access to those variable here is my code :


import zio._

class Rectangle(val width: Int,val height: Int) {

  val x: UIO[Ref[Int]] = Ref.make(0)
  val y: UIO[Ref[Int]] = Ref.make(0)

  def this(x1: Int, y1: Int, width: Int, height: Int) {
    this(width, height)

    for {
      ref <- this.x
      _ <- ref.set(x1)
    } yield ()

    for {
      ref <- this.y
      _ <- ref.set(y1)
    } yield ()
  }

}

in order to access the Ref I wrote this :

import zio.console._
import zio._

object AccessRef extends App {
  val myRec = new Rectangle(1, 2, 3, 4)

  override def run(args: List[String]) =
    for {
      rec <- IO.succeed(myRec)
      x <- rec.x
      x1 <- x.get
      _ <- putStrLn(x1.toString)
      _ <-putStrLn(rec.height.toString)
    } yield (0)
}

the output:

0
4

I'm wondering why the value of ref couldn't been updated to 1 rather it 0 ?

simpadjo
  • 3,947
  • 1
  • 13
  • 38
NaseemMahasneh
  • 485
  • 5
  • 19

1 Answers1

3

val x: UIO[Ref[Int]] = Ref.make(0) is not a reference. It is a description of an action that returns you a reference.

This code

for {
      ref <- this.x
      _ <- ref.set(x1)
    } yield ()

creates a reference, sets a value to it and immediately discards the reference. Most probably you'd want to have x and y be of type Ref[Int].

Example:

import zio.console._
import zio._

class Rectangle(val width: Ref[Int], val height: Ref[Int])

object AccessRef extends App {

  override def run(args: List[String]) =
    for {
      recW <- Ref.make(3)
      recH <- Ref.make(5)
      rectangle = new Rectangle(recW, recH)
      oldHeight <- rectangle.height.get
      _ <- putStrLn(s"old value: $oldHeight") //5
      _ <- rectangle.height.set(30)
      newHeight <- rectangle.height.get
      _ <- putStrLn(s"new value: $newHeight") //30
    } yield (0)
}
simpadjo
  • 3,947
  • 1
  • 13
  • 38
  • if I declare ````x```` and ````y```` of type ````Ref[Int]```` I can't set the value to ````x1```` and ````y1```` !! do you have any idea about how I can update their values ? – NaseemMahasneh Jul 30 '19 at 07:49
  • 1
    An alternative to having two Refs could be to have a regular immutable `Rectangle(x,y,w,h)` and put the whole thing into a `Ref[Rectacle]`. Fewer moving parts, atomic updates and all that. – Thilo Jul 30 '19 at 09:08
  • 1
    You can. But modification of a `Ref` introduces an `IO` effect. I updated my answer with an example. – simpadjo Jul 30 '19 at 09:09
  • @simpadjo thank you it works . The last thing that's still foggy to me is how I can give the ````Ref```` an initial value inside the constructor let say I want to set the height to 0 in the *class definition* how to do that ? – NaseemMahasneh Jul 30 '19 at 10:35
  • 1
    Allocating a `Ref` and setting a value are effectful operations. Once you do it you are in `IO`. So it's not possible to create a `Ref` in constructor. Although you could write a factory method instead: `def createRect(w: Int, h: Int): UIO[Rectangle] = for {recW <- Ref.make(h) ; recH <- Ref.make(w)} yield new Rectangle(recW, recH)` – simpadjo Jul 30 '19 at 12:42