Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Felix Dietze
    @fdietze
    @SRGOM that makes sense, thank you. The scala compiler provides syntactic sugar for apply() and update(): http://otfried.org/scala/apply.html, so a() = 5 is exactly the same as a.update(5)
    Probably interesting for everyone: I think we have a bit too many reactive dom libraries with the same goals: scala-js/scala-js#2843 What do you think?
    S
    @SRGOM
    I like scala.rx- You can learn it in 30 minutes. While I did battle it for a day in absense of any DOM example (which later told me how to add the ctx) it still beats anything else.
    Jean-Philippe Pellet
    @jppellet

    I'm trying the first example and it fails:

        val a = Var(1)
        val b = Var(2)
        val c = Rx { a() + b() }
        println(c.now) // 3
        a() = 4
        println(c.now) // 6

    fails with: This Rx might leak! Either explicitly mark it unsafe (Rx.unsafe) or make an implicit RxCtx available

    The docs don't seem to indicate I need to provide a Ctx in this case. And if I provide one, I'm afraid to override accidentally others that are supposed to be generated by macros at other places. Any hint?
    Jean-Philippe Pellet
    @jppellet
    Looks like the test classes use import Ctx.Owner.Unsafe._
    Felix Dietze
    @fdietze
    @jppellet I'm using: implicit val ctx: Ctx.Owner = Ctx.Owner.safe()
    Jean-Philippe Pellet
    @jppellet
    @fdietze OK, what's the difference? Yours is produced by a macro which seems to look for a safe context but fails when there isn't. So at the root of your app, don't you need to use unsafe somewhere?
    Felix Dietze
    @fdietze
    @jppellet I only have this line once at the root of my project
    I don't exactly know what's the difference
    S
    @SRGOM
    @fdietze I was just going through your google groups discussion and I would agree with you and say (here, don't want to use google groups) that I understand and partially share your concern. My fear was that scala-js has too little people working relative to the goods it offers and wish that the efforts were in sync. I don't have any numbers on scala-js usage, nor do I know if we're gathering a bigger audience and at what rate, but I would say that if our numbers are increasing then surely I (and I'm guessing you too?) don't mind this explosion since the number in a way legitimizes the existence of scala.js
    Felix Dietze
    @fdietze
    @SRGOM I agree with you. A huge audience would justify this kind of diversity. But I believe that we don't have enough library developers to have ~7 different libraries with the same goals.
    Zoo Sky
    @zoosky
    @lihaoyi what's the state of this project?
    Li Haoyi
    @lihaoyi
    it works, feel free to use it
    Fabian Schmitthenner
    @fkz
    @Voltir @lihaoyi hey, may you have a look at this issue #89, please?
    Nick Childers
    @Voltir
    Thanks for the sample @fkz - I can find some time to poke at it at the very least, and try to figure out way it happens
    Fabian Schmitthenner
    @fkz
    @Voltir Have you been able to reproduce it?
    Nick Childers
    @Voltir
    @fkz Yea - I was able to repo it, how very interesting
    Nick Childers
    @Voltir
    it looks to be related to something about mapping Rx'es..
    to be fair, I wrote that before I knew what the functor laws were.. i should probably revisit that code to make sure those things are lawful!
    Fabian Schmitthenner
    @fkz

    I don’t think this has anything to do with map or functor laws, as replacing map with the corresponding Rx construct leads to the same problem:

    import $ivy.`com.lihaoyi::scalarx:0.3.2`, rx._
    object Example {
    val v1 = Var(0)
    val v2 = Rx { v1() }
    val v22 = Rx { v1() }
    val v23 = Rx { v22() }
    val v3 = Rx { v23() }
    def q(implicit trackDependency: Ctx.Data) = {
        if (v1() == 0) v2()
        else {
          val b = v3() != v2()
          if (b)
            103
          else
            17
        }
      }
    val v = Rx { q }
    val list = {
        var result = List.empty[Int]
        val obs = v.trigger { result = result :+ v.now }
        v1() = 1
        v1() = 2
        result
      }
    }
    println(Example.list)

    This prints List(0, 103, 17) instead of List(0, 17), too.

    Felix Dietze
    @fdietze
    Hi, does anyone know which guarantees regarding frp glitches and multiple updates I get in a synchronous setting?
    Roland Reckel
    @rreckel

    Hi,
    I've got a problem with calling Futures out of Rx.
    Just copy and paste the following code into ScalaFiddle:

    import rx._
    import rx.async._
    import scala.concurrent.Future
    import scala.concurrent.Promise
    import scala.concurrent.ExecutionContext.Implicits.global
    
    def request(id: Int): Future[String] = {
      val p = Promise[String]()
      js.timers.setTimeout(500) {
        println(s"Request: $id")
        p.success(id.toString)
      }
      p.future
    }
    
    val id = Var[Int](0)
    val idString = id.flatMap(i => request(i).toRx("...")) 
    
    id() = 10
    println("End...")

    And you fall into a loop, with the following output:

    End...
    Request: 0
    Request: 10
    Request: 10
    Request: 10
    Request: 10
    Request: 10
    Request: 10
    Request: 10
    etc....

    Is this a known behaviour? or is this a bug?
    Is there a workaround for this kind of pattern?

    Thanks for your help.
    Roll

    Nick Childers
    @Voltir

    @rreckel Yea, currently the way flatMap works, it recreates the inner rx whenever the inner rx changes - this interacts poorly with toRx because, as you see in your test, it throws it in an infinite loop.

    Im having a hard time coming up with an alternate definition of toRx that actually works within flatmap and am considering just removing it all together.

    Nick Childers
    @Voltir

    So ive been playing around with alternatives, and this seems to work:

      implicit class FutureCombinators[T](val v: rx.Rx[Future[T]]) extends AnyVal {
        def flatten(initial: T)(implicit ec: ExecutionContext, ctx: Ctx.Owner): Rx[T] = {
          var result = Var(initial)
          v.foreach { x => x.foreach(result.update) }
          result
        }
      }

    And its used this way:
    id.map { x => request(x) }.flatten("...")

    @rreckel would something like that work? @fdietze what do you think?
    Nick Childers
    @Voltir
    Bleh, that actually doesnt work if you end up having the flattened future inside of a flatMap
    Roland Reckel
    @rreckel

    I tried your flatten function:

    import rx._
    import rx.async._
    import scala.concurrent.Future
    import scala.concurrent.Promise
    import scala.concurrent.ExecutionContext
    
    implicit class FutureCombinators[T](val v: rx.Rx[Future[T]]) extends AnyVal {
      def flatten(initial: T)(implicit ec: ExecutionContext, ctx: Ctx.Owner): Rx[T] = {
        val result = Var(initial)
        v.foreach { x => x.foreach(result.update) }
        result
      }
    }
    
    def request(id: Int): Future[String] = {
      val p = Promise[String]()
      js.timers.setTimeout(500) {
        println(s"Request: $id")
        p.success(id.toString)
      }
      p.future
    }
    
    import scala.concurrent.ExecutionContext.Implicits.global
    
    val id = Var[Int](0)
    val idString = id.map(i => request(i)) .flatten("...")
    
    val result = for {
      i <- id
      is <- idString
    } yield s"$i -> $is"
    
    result.foreach(println(_))
    
    id() = 10
    id() = 20
    println("End...")

    This code generates the following result in ScalaFiddle:

    0 -> ...
    10 -> ...
    20 -> ...
    End...
    Request: 0
    20 -> 0
    Request: 10
    20 -> 10
    Request: 20
    20 -> 20

    This is not exactly what I expected..... but still better than an infinite loop ;-)
    What do you think?

    Nick Childers
    @Voltir
    Interesting - I tried a similar test but had the map/flatten in the for loop and that created an infinite loop
    Maybe this and a section in the readme explaining this is sufficient?
    Felix Dietze
    @fdietze
    Are you trying with a 0.3 version or with latest master? To me it looks like the flatMap leak, which we fixed recently.
    Roland Reckel
    @rreckel
    I am using version 0.3.2
    I integrated the flatten function in my project now, and I don't have any loops anymore.
    Does an "official" latest version of scala.rx exist? I often try some snippets of code in ScalaFiddle but there the only version is 0.3.2
    Anyway I can test the code with the latest master and keep you informed.
    Roland Reckel
    @rreckel

    Hi again,
    I am sorry to report that the latest master does not resolve the loop in flatMap with toRx.
    The following script can be executed in ammonite:

    import $ivy.`com.lihaoyi::scalarx:0.4.0-SNAPSHOT`, rx._, rx.async._
    import Ctx.Owner.Unsafe._
    
    import scala.concurrent._
    import scala.concurrent.duration._
    import scala.concurrent.ExecutionContext.Implicits.global
    
    object FlatMap {
    
      def test() = {
        def request(id: Int): Future[String] = Future {
          Thread.sleep(500)
          println(s"Request: $id")
          id.toString
        }
    
        val id = Var[Int](0)
        val idString = id.flatMap(i => request(i).toRx("..."))
    
        id() = 10
        id() = 20
        println("End...")
        Await.result(Future{Thread.sleep(3000); println("Waited long enough")}, 30 seconds)
      }
    }
    
    FlatMap.test()

    and produces the following output:

    End...
    Request: 0
    Request: 10
    Request: 20
    Request: 20
    Request: 20
    Request: 20
    Request: 20
    Waited long enough
    Request: 20
    Felix Dietze
    @fdietze
    @rreckel Could you please open a PR with a failing test case?
    Nick Childers
    @Voltir
    I've been trying to tackle this problem - it's not the same issue as the flatmap problem. It also seems really hard to solve in a satisfying way.
    Making futures compose nicely in Rx contexts is hard because the re-evaluation step recreates the future, creating the cycle of infinite loop
    Roland Reckel
    @rreckel
    Call me crazy, but would it be possible to create a "toRx" function for Monix Task? Would that be easier perhaps, as those are lazy evaluated?
    I guess I will have to look at the scala.rx code a bit.
    Nick Childers
    @Voltir
    Sure - I think that's possible
    Perhaps something akin to how sttp does its effect encoding https://github.com/softwaremill/sttp
    I wouldn't want to add a dependency to monix in the core repo though
    Roland Reckel
    @rreckel
    You are right.... adding a dependency is not good.
    Nick Childers
    @Voltir
    What gives me hope is that toRx does appear to work if the definition is outside of the flatmap - I think if I can make the flatmap macro generate the equivalent of that, we might finally have a decent solution
    Minghao Liu
    @molikto
    @  val a = Var(1)  
    
    a: Var[Int] = Var@70(1)
    
    @  
    
    @ val b = Var(2)  
    b: Var[Int] = Var@6b(2)
    
    @  val c = Rx { println("c triggered "+ ( a() + b()))}  
    c triggered 3
    c: Rx.Dynamic[Unit] = Rx@2e(())
    
    
    @  
    
    @ a.kill() 
    
    
    @ b() = 3 
    c triggered 4
    
    
    @ a() = 5 
    c triggered 8
    so seems kill() doesn't work on Var?
    Nick Childers
    @Voltir
    @molikto ah, thats interesting - what happens if you dont do the b() = 3 step?
    kill on a Var just clears the downstream listeners - Vars dont really have an owner. What I think happens is when you trigger a re-evaluation of c via b() = 3, the dependency c has on a is just recreated. I guess "kill" is kind of a misleading name for what actually happens on a Var.