question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Structural `dropRepeat` mechanism and unexpected repeats

See original GitHub issue

This is more of a discussion rather than a direct issue, but as there is a fair amount to say I bring it up here instead of gitter.

The basic idea is that Rx.dropRepeat is fine for values but not fine for objects in general.

The problem might be avoided with a call to Rx.foldp; here is a real example that isn’t (too) long:

  val currentApiUri: Rx[URI] = (checkApiUri(localApiUri)
    |@| apiUriApp.app._2.flatMap(uri => checkApiUri(uri.toString))
    ).map{
    case (Some(lUri), Some(sUri)) => sUri
    case (Some(lUri), None) => lUri
    case (None, Some(sUri)) => sUri
    case (None, None) => defaultUri
  }.foldp(defaultUri){(curUriObj, newUriObj) =>
    if (curUriObj.toString == newUriObj.toString) curUriObj
    else newUriObj
  }.dropRepeats.map{ capiUri =>
    // DEBUG
    println(s"current API URI is $capiUri; hash = ${System.identityHashCode(capiUri)}")
    capiUri
  }

The problem with foldp here is that curUriObj doesn’t come from the current value of currentApiUri itself, but rather from its input sources:

(checkApiUri(localApiUri)
    |@| apiUriApp.app._2.flatMap(uri => checkApiUri(uri.toString))
    )

In our case, since checkApiUri creates and returns a new URI object every time it is called, foldp always updates. A relevant part of the web console looks like this for a particular route:

"current API URI is http://localhost:8081/ced2ar-rdb/api; hash = 25"  Dynamic.scala:78:70
"current API URI is http://localhost:8081/ced2ar-rdb/api; hash = 26"  Dynamic.scala:78:70
"current API URI is http://localhost:8081/ced2ar-rdb/api; hash = 27"  Dynamic.scala:78:70
"current API URI is http://localhost:8081/ced2ar-rdb/api; hash = 28"  Dynamic.scala:78:70

An alternative is to define a version of dropRepeats that maintains an internal Var so that Var.update can be called. However, this ends up being a bit tricky, but perhaps it can be simplified (especially if internalized to monadic-rx, I suspect):

  case class Comp[A](oldA: A, newA: A)
  def dropRepeat[A](init: A, rx: Rx[A], keep: Comp[A] => Boolean): Rx[A] = {
    object holder {
      val hvar = Var(init)
      val cc: Cancelable = rx.impure.foreach(newVal => hvar.update(curVal =>
        if (keep(Comp(oldA = curVal, newA = newVal))) curVal else newVal
      ))
      override def finalize(): Unit = {
        try cc.cancel
        finally super.finalize()
      }
    }
    holder.hvar.dropRepeats
  }

  def keepUri(uris: Comp[URI]): Boolean = uris.oldA == uris.newA

  val currentApiSource: Rx[URI] = (checkApiUri(localApiUri)
    |@| apiUriApp.app._2.flatMap(uri => checkApiUri(uri.toString))
    ).map{
    case (Some(lUri), Some(sUri)) => sUri
    case (Some(lUri), None) => lUri
    case (None, Some(sUri)) => sUri
    case (None, None) => defaultUri
  }

  val currentApiUri: Rx[URI] = dropRepeat(defaultUri, currentApiSource, keepUri)
    .map{ capiUri =>
    // DEBUG
    println(s"current API URI is $capiUri; hash = ${System.identityHashCode(capiUri)}")
    capiUri
  }

In particular, I’m dubious about my use of finalize, but I hope that at least demonstrats what I hope is happening…

I’m also a bit surprised that, in this case, the different URI objects apparently evaluate as being unequal in case DropRep(self) => in rx.scala, though maybe this isn’t what is happening. Nonetheless, Rx.dropRepeats is apparently not sufficient to prevent multiple emissions with the same URI (capiUri) but different hashcodes in the first example/println above.

When we test URI equivlance we get what we expect in the Scala repl:

scala> val uriA = new URI("https://www.ibm.com/us-en/")
uriA: java.net.URI = https://www.ibm.com/us-en/

scala> val uriB = new URI("https://www.ibm.com/us-en/")
uriB: java.net.URI = https://www.ibm.com/us-en/

scala> uriA == uriB
res0: Boolean = true

The equivalent web console output for our new dropRepeat function is :

"current API URI is http://localhost:8081/ced2ar-rdb/api; hash = 19" Dynamic.scala:78:70

However, this happens 9 times for the same route, and is even more surprising since it is being executed 9 times, even though each URI has the same URI string and hash code. In my code, all these definitions are in a top-level object, so I don’t see multiple instance creation being a factor in causing repeated identical messages.

I’m at a bit of a loss. If nothing obvious comes up, I can try to convert some of this into unit test to see if that may help identifying (or at least sharing) the issue.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:16 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
fizzy33commented, Oct 31, 2017

I think the point of good tests is to beat things to death 😃

1reaction
bbarkercommented, Oct 20, 2017

@fizzy33 I admit I was wondering about that, but at least in this simple case == works as expected in scala.js: https://scalafiddle.io/sf/nnfr0VI/0 , but I’ll investigate at bit more along those lines.

@OlivierBlanvillain Yeah, I also doubt it is dropRepeats causing the problem … I looked at the simple implementation and thought the same. However, I do think it would be nice to have a dropRepeats that can inspect its current value using a specified “keep” function.

It makes sense to me that you’d want to dropRepeates after a flatMap, and not inside of flatMap, but don’t see anything obvious popping up here (the only flatMap in my code is the one you see) - I’ll see if I can make a minified example

Read more comments on GitHub >

github_iconTop Results From Across the Web

On the wrong DNA track: Molecular mechanisms of repeat ...
In this review, we first describe the molecular mechanisms of repeat-induced toxicity, which is the connecting link between repeat expansions ...
Read more >
Unexpected formation of parallel duplex in GAA and TTC ...
One hypothesis is that the trinucleotide repeats form a stable non-B-DNA structure(s), which can lead to aberrant DNA replication, repair, or recombination ( ......
Read more >
Losing DNA methylation at repetitive elements and breaking bad
Interspersed repeats are repeated sequences wherein the single copies are scattered in the whole genome with the capability to move from a ...
Read more >
Creating Drop Repeats - Artlandia
This tutorial walks you through the simple steps of creating drop repeats. The half-drop repeat. The half-drop repeat is built in so it...
Read more >
Unexpected Mutations by CRISPR-Cas9 CTG Repeat ...
Messenger RNAs containing these expanded repeats form aggregates as nuclear RNA foci. Then, RNA binding proteins, including muscleblind-like 1, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found