Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Sep 05 2019 14:43
    @typelevel-bot banned @jdegoes
  • Jan 31 2019 21:17
    codecov-io commented #484
  • Jan 31 2019 21:08
    scala-steward opened #484
  • Jan 31 2019 18:19
    andywhite37 commented #189
  • Jan 31 2019 02:41
    kamilongus starred typelevel/cats-effect
  • Jan 30 2019 00:01
    codecov-io commented #483
  • Jan 29 2019 23:51
    deniszjukow opened #483
  • Jan 29 2019 23:37
  • Jan 29 2019 23:22
  • Jan 29 2019 20:26
    Rui-L starred typelevel/cats-effect
  • Jan 29 2019 18:01
    jdegoes commented #480
  • Jan 29 2019 17:04
    thomaav starred typelevel/cats-effect
  • Jan 28 2019 17:43
    asachdeva starred typelevel/cats-effect
  • Jan 28 2019 07:12
    alexandru commented #480
  • Jan 28 2019 05:45
    codecov-io commented #482
  • Jan 28 2019 05:35
    daron666 opened #482
  • Jan 27 2019 13:56
    codecov-io commented #481
  • Jan 27 2019 13:46
    lrodero opened #481
  • Jan 27 2019 05:47
    codecov-io commented #460
  • Jan 27 2019 05:37
    codecov-io commented #460
Michael Pilquist
@mpilquist
(ResourceProxy stuff we’ve discussed a few times)
underscore05
@underscore05
I would like to seek help refactoring this code. I don't know if should wrap the ValidatedNec to IO or what... I also wanted to have a logger on every validation.
type ValidationResult[A] = ValidatedNec[JobPostError, A]

override def createJobPost(
    newJobPost: JobPost
): IO[ValidatedNec[String, JobPost]] = {
  // TODO: Add logger here on every field validation
  val localValidation: ValidationResult[JobPost] = (
    validateNoop(newJobPost.id),
    validateEmptiness("Job post title".some, newJobPost.title),
    validateEmptiness("Job post description".some,
                      newJobPost.description),
    validateNoop(newJobPost.createdAt),
    validateNoop(newJobPost.modifiedAt)
  ).mapN(JobPost)

  val databaseValidations: IO[ValidationResult[JobPost]] = (for {
    _ <- Logger[ConnectionIO].info("Validating job title")
    title <- validateTitleExistence(newJobPost)
    _ <- Logger[ConnectionIO].info("Validating job description")
    description <- validateNoop(newJobPost.description).pure[ConnectionIO]
    createdAt <- validateNoop(newJobPost.createdAt).pure[ConnectionIO]
    modifiedAt <- validateNoop(newJobPost.modifiedAt).pure[ConnectionIO]
    id <- validateNoop(newJobPost.id).pure[ConnectionIO]
  } yield {
    (id, title, description, createdAt, modifiedAt).mapN(JobPost)
  }).transact(xa)

  val response: IO[ValidatedNec[String, JobPost]] =
    localValidation match {
      case Valid(_) => databaseValidations.map(_.leftMap(_.map(_.errorMessage)))
      case Invalid(e) => e.map(_.errorMessage).invalid[JobPost].pure[IO]
    }
  response
}
Oleg Pyzhcov
@oleg-py
@underscore05 is noop always valid, and is it temporary or there to stay?
underscore05
@underscore05
@oleg-py this one is just temporary since I don't have validation rules for them yet.
Or is there much better way to do this in case that I just want to validate some of the case class fields?
Oleg Pyzhcov
@oleg-py
Yeah, you just... don't check them. And if you don't alter the value, you don't need mapN either:
val localValidation = validateEmptiness(...) *> validateEmptiness(...) *> newJobPost.validNec
actually you never use the Valid case in your result, so you don't even need the last clause
Oleg Pyzhcov
@oleg-py
For doing DB validations, it really depends on how much you need to query and how soon do you want to stop.
underscore05
@underscore05
@oleg-py in my case will it execute all query before performing validation on the yield part?
Oleg Pyzhcov
@oleg-py
Yes, and if you have just one query, you'd probably be better off ditching for-comprehension
underscore05
@underscore05
Ok man, thank you
Paul Snively
@paul-snively
Also, consider some sort of Merge typeclass for updating a value with defaults.
Luka Jacobowitz
@LukaJCB
Merge? Is that just a less fancy way of saying Semilattice?
Or Band
Gavin Bisesi
@Daenyth
Is there any sort of stance on adding "duplicate" methods in more discoverable locations? An example I'm thinking of is adding IO.parSequence or parSequenceN. It's not immediately obvious where that behavior lives if you're using IO directly and not the typeclasses. Even with the typeclasses, parSequence and parSequenceN for example exist in different typeclasses, and it's not necessarily obvious to a newcomer why that might be
I'm writing some aimed-at-beginners info around IO and some cases like that make things less discoverable than I'd want it to be
Other examples might be typeclass methods/syntax on IO as direct methods; things like >> or adaptError
The "tax" of needing the cats.implicits._ import in order to get the "full" API for IO is a little unfortunate I think
It's not wrong, which is why I ask if there's a stance on it, or if it's just been organic and ad-hoc as to which things get added where
Paul Snively
@paul-snively
@LukaJCB: I took the point of the suggestion at the link to be that it's easy to provide a typeclass and automatic derivation of it for types Shapeless can automatically derive it for, but I have to confess to not being familiar enough with Semilattice or Band to comment.
@LukaJCB: Other than perhaps to observe that I've seen some papers saying "Hey, CRDTs are bounded semilattices!" But few to no Scala CRDT libraries reflecting that, or uses of Semilattice or Band, for that matter.
Gavin Bisesi
@Daenyth
Does anyone have an example of code that deadlocks with unsafeRunSync() given a single thread but works with unsafeToFuture()?
Does that even make sense?
Paul Snively
@paul-snively
@LukaJCB: To be very frank, over the last few years, I've been... underwhelmed... by the state of Scala's ecosystem around a really sophisticated understanding of data, in the sense of, e.g. https://www.cs.indiana.edu/~dgerman/2008midwestNKSconference/tarau_paper.pdf
Ryan Peters
@sloshy
@Daenyth depends, does the deadlock only occurring w/ tut or the repl due to a bug count? :)
the one in the FS2 FAQ in particular
Gavin Bisesi
@Daenyth
@sloshy I don't have a snippet, I wanted to show an example of why you shouldn't use unsafeRunSync()
without something "obvious" like Semaphore
Fabio Labella
@SystemFw
@Daenyth use TextContext
Gavin Bisesi
@Daenyth
Thanks
Piotr Gawryś
@Avasil

Is there any sort of stance on adding "duplicate" methods in more discoverable locations?

I think the idea was to keep it as minimal as possible to ease maintenance.
I don't know what's the current stance on this. In my opinion methods on IO improve user experience and allow optimization opportunities. People not using IntelliJ (or with better computer) can argue discoverability part because they can always import cats.implicits._ but that's not the case with me. IMO methods on IO + passing thread pool only at execution/evalOn (coming in 3.x I suppose) are two things that are really convenient for users.

Daniel Spiewak
@djspiewak

I don't know what's the current stance on this. In my opinion methods on IO improve user experience and allow optimization opportunities. People not using IntelliJ (or with better computer) can argue discoverability part because they can always import cats.implicits._ but that's not the case with me. IMO methods on IO + passing thread pool only at execution/evalOn (coming in 3.x I suppose) are two things that are really convenient for users.

This is my view of things. IMO IO should have specific versions of most of the common functions, even if we can inherit them from typeclasses, and the typeclass instances should override to point to our duplicates

There are a number of advantages to this, not the least of which is reducing the import tax.
It's like, for example, the fact that we define IO#map despite the fact that we could just inherit it from Functor via Monad. Part of that is for efficiency, of course, but there are other functions which are similar to this
Ivan Aristov
@Ssstlis
Hi all. I have some stupid question. I wanna run some racing IO using the Concurrent Object-companion directrly. So, the ContextShift that needs to this operation is the context for execution the background fibers or context for back down from fibers? Thanks!
The example code:
  import retry._
  import retry.CatsEffect._
  import cats.effect.IO.ioConcurrentEffect
  import cats.implicits._
  import scala.concurrent.duration._

  val policyDB: RetryPolicy[IO] = limitRetries[IO](5) join RetryPolicies.constantDelay(50 milliseconds)

  def handler(implicit log: LogAlg, sentry: SentryAlg): (Throwable, RetryDetails) => IO[Unit] = (ex, st) => {
    st match {
      case RetryDetails.GivingUp(retries, delay) =>
        val message = ex.getMessage
        val exc = new Throwable(s"DB policy is giving up after $retries retries and $delay delay with message: '$message'", ex)
        sentry.sendException(exc)
      case RetryDetails.WillDelayAndRetry(delay, retries, overDelay) =>
        log.error(s"DB policy is so far got $retries retries with $overDelay over delay, start next try after $delay delay")
    }
  }

  def queryRunner[T](implicit timer: Timer[IO], cs: Const[ContextShift[IO], RaceDb], log: LogAlg, sentry: SentryAlg): Endo[IO[T]] = {
    (Concurrent.timeout(_: IO[T], 4 seconds)(ioConcurrentEffect(cs.getConst), timer)) >>>
    retryingOnAllErrors[T](policyDB, handler.apply)
  }
Fabio Labella
@SystemFw
the ContextShift is there for execution
Ivan Aristov
@Ssstlis
Thank you!
Fabio Labella
@SystemFw
you can take Concurrent[IO] instead
of F[_]: Concurrent: Timer
which is arguably more correct
Concurrent is the typeclasses that provides racing

ioConcurrentEffect(cs.getConst)

this is potentially weird, but I'm going to assume you have a good reason for it :)

Ivan Aristov
@Ssstlis
I know this is bad, but i wanna run queries for DB it another ThreadPool.
Maybe i going to extract value from Const to another implicit value
Fabio Labella
@SystemFw
ok, then no
that's not how you do it
forget about the Const
do not pass instances implicitly