evolution-gaming / cats-helper

Helpers for cats & cats-effect
MIT License
51 stars 17 forks source link

Add a way to create log without side effects #116

Open FunFunFine opened 3 years ago

FunFunFine commented 3 years ago

Currently LogOf creates desired Log instances with a side-effect. But there is a simple way to avoid that and get plain Log[F], not F[Log[F]]. This is possible because of the fact that both SLF4J and Logback cache their loggers (which LogOf relies on). This means that it is totally fine to call loggerFactory.getLogger(source) on each log message, because the overhead is simply a hash table call and a couple of if-s.

The names and the details in this PR are subject to change, let's discuss it all.

FunFunFine commented 3 years ago

One important thing to discuss is how to integrate it in existing code. If LogOf had two type-parameters, then it would be simpler: just make a LogOf[Id, F] returning method. But it doesn't hence we need to create another one. Should we even force the migration to this new version, if it is any good?

t3hnar commented 3 years ago
trait MyClass[A[_], B[_], C[_]] {
  def a: A[…]
  def b: B[…]
  def c: C[…]
}

gives the most flexibility, however usually you just do not need that, basically single F[_] is the most common case without over complications. Different might not even give you composability :)

hence I'd recommend to NOT overcomplicate, imho .toTry.get will be simpler :)

FunFunFine commented 3 years ago

hence I'd recommend to NOT overcomplicate, imho .toTry.get will be simpler :)

I do not want to make my code impure. .toTry.get won't work for me unfortunately.

FunFunFine commented 3 years ago
```scala
trait MyClass[A[_], B[_], C[_]] {
  def a: A[…]
  def b: B[…]
  def c: C[…]
}

gives the most flexibility, however usually you just do not need that, basically single F[_] is the most common case without over complications.

Regarding multiple type parameters: I was talking about such approach:

trait LogOf[I[_], F[_]] {
  def apply(source: String): I[Log[F]]
}

where I denotes your initialisation effect and F is your main effect where your app runs. For example, I =:= IO & F =:= ReaderT[IO, MyRequestContext, *], when your app runs in some contextual environment (e.g. context extracted from HTTP request).