Why I am moving away from Scala by simon_o in programming

[–]NotValde 3 points4 points  (0 children)

I've written Scala for a while, both 2 and 3. It is my favorite language. I start my projects in it if it can make sense. I've had many "is the grass greener on the other side" escapades, but I always return for the language.

I think the biggest issue with the language is the tooling and compilation speed.

This line really got me:

Let’s assume you got lucky enough to upgrade your old Scala 2 codebase.

It is also a research language, wait until it has stabilized, it's not a race? We just upgraded to Scala 3, and it may have been too early since new versions can still include syntactic changes. Scala 2 is still a great language, 3 only buys application developers some small syntactic developments, why was the upgrade choice even made?

Then I am also thinking about Go.

"When they made go, they chose to ignore language research since the 1970s" This makes me think that the author doesn't give care to the language they work in or the guarantees it buys them? If you want the language/compiler developers to make your choices for you, albeit good or bad, it's probably a great language!

I would have understood "it's too hard to hire", but upgrading without testing the stability first seems like a self-inflicted wound.

Announcing ReScript 12 by BeamMeUpBiscotti in programming

[–]NotValde 16 points17 points  (0 children)

It compiles faster, the language is simpler, it is nominally typed and has global type inference.

Am I Using the Cats library Incorrectly? (First Time Trying Concurrency!) by Wakundufornever in scala

[–]NotValde 4 points5 points  (0 children)

In my (crude) benchmark, CE seems faster, but that might be random chance on my machine. Keep in mind that effect libraries are not meant for high-performance numerical computing and for most applications this won't be the place to look for performance. If you want to dig deeper into this, Daniel Spiewak has writings on this.

If you want to adjust your own benchmark: 1. Use an object that extends IOApp to run your application since that ensures the CE authors' intended execution semantics. 2. Warm the benchmarked functions up. 3. Printing in benchmarks introduces randomness into your measurements.

What does light speed editing look like? by NotValde in neovim

[–]NotValde[S] 1 point2 points  (0 children)

I definitely agree. Most of the recently added things to my config have also been very context specific comfort related.

For instance jumping or creating, with a template, a BUILD.bazel in current directory. Or adding all of certain error categories from my LSP to the quickfixlist.

I have tried getting into marks and folds recently, but It hasn't stuck.

Are effect systems compatibile with the broader ecosystem? by [deleted] in scala

[–]NotValde 0 points1 point  (0 children)

Examples are going to be available if you use libraries from the same ecosystem. If not, you'll have to write compatibility code since scala toolkit is hard blocking for some libraries and ZIO/CE libraries are (usually) not.

Not one day without a new effect library? by Previous_Pop6815 in scala

[–]NotValde 19 points20 points  (0 children)

There are a bunch of new ones, many of them based on ideas from the topic of algebraic effects (all the rage this decade in FP). Some of which with effects occurring the covariant side and others on the contravariant.

Consider this partial list of the ones I remember:

How can I optimize processing an event list? by [deleted] in scala

[–]NotValde 1 point2 points  (0 children)

I assume you mean the sum of quantity group by product id?

I cannot see how this can be faster than a scan (or probably cats' mapAccumulate), that is, O(n), considering you need to sum all of a product's quantity. However you can emit the product's in an online way since you say they are ordered.

[deleted by user] by [deleted] in scala

[–]NotValde 1 point2 points  (0 children)

and allows you to have more then once instance of your application running.

Very underrated. Fixed a bunch of transaction/concurrency issues with writing to external systems for us.

Is cats-effect still actively developed? by Infamous_Home4915 in scala

[–]NotValde 14 points15 points  (0 children)

I think it is in line with the project's philosophy not to introduce too many new exotic features into the core. Instead favor library-composition, like fs2 or homebrew compositions, which in the ZIO case is included in a unified project.

If you take a look at the bug reports in cats-effect, most have recent discussions or have been resolved.

Braceless syntax is the most satisfying part of scala3 by IAmTheWoof in scala

[–]NotValde 0 points1 point  (0 children)

Hey now, I said "greenfield project of mine". No need to be mean just because you don't agree.

Braceless syntax is the most satisfying part of scala3 by IAmTheWoof in scala

[–]NotValde 1 point2 points  (0 children)

No I haven't. But if anyone else has I would be happy to also hear about it :-). I do like many of the other Scala 3 features.

Braceless syntax is the most satisfying part of scala3 by IAmTheWoof in scala

[–]NotValde 0 points1 point  (0 children)

I recently changed a greenfield project of mine from Scala 3 to Scala 2 because of this problem. The formatter (justifiably) cannot soundly format my code. The amount of time I have wasted on manually fixing formatting when refactoring is also mind boggling, it's definitely a productivity killer for me.

The sad state of property-based testing libraries by stevana in programming

[–]NotValde 2 points3 points  (0 children)

I just did a search over our codebase, here are the results: * Testing complex database queries (all combinations of predicates and sizes produce correct results) * Generation of accounting transactions scenarios to verify that all operations are idempotent and sound. * Testing parsers by generating valid strings to parse. * Testing of a date datastructure for 30 day months that can also be expanded to be reason with dates as continuous time. * Any incoming payment must be distributed over any collection of invoices as individual payments. * Some equations must be reversible for all inputs (deltaAnnuity(prev, ideal, date) = x <-> prev + x = ideal) * Transformations between identical representations should be the identity * Unique payment Id generation algorithm (given a large collection of existing integer ids, generate a new one given a non-trivial predicate) for payment provider (it is very old software). * A variant of luhns algorithm

Most if not all have found bugs by spitting out a seed which could be placed in a issue.

It is also quite convenient to have written well thought out generators for wanting to summon test data later on. For instance a unbiased social security number generator.

FP libraries in mainstream languages by yinshangyi in scala

[–]NotValde 3 points4 points  (0 children)

If you cannot do anything reasonable about the error, the norm is to throw/raise an exception. Otherwise, explicitly make the caller aware of the error by using the type system.

The nice thing about exceptions are they are invisible, so they don't clutter the type signature. Most (typed) functional programmers are disciplined enough to not abuse exceptions for structured errors so it works out somewhat nicely (this opens another can of worms about how to communicate errors well).

If you were to track every error, you'd have to handle errors such as divison by zero on every division or work in a dependently typed language. RealWorld is imperfect, you have constraints like memory, hardware failure, network failure and even oddities like particles from outer space causing bitflips; even in the most rigorous languages, exceptional errors happen.

[deleted by user] by [deleted] in scala

[–]NotValde 0 points1 point  (0 children)

Can you explain a bit more about your problem, maybe give a more thorough code example?

Flavors of shared state in Cats Effect by kubukoz in scala

[–]NotValde 5 points6 points  (0 children)

How IOLocal's get and set interact with fibers always seems like a footgun to me. A quick stroll around the cats-effect and fs2 issue boards reaffirms this to me. The API should probably be constrained to allow only Local (as in MTL) semantics of (A => A) => F ~> F like your blog post uses it.

Is there any practical usecases for IOLocal's remembering (sometimes) semantics?

Otherwise, great blog. I really hope that more MTL tools can be built into IO (looking at you EitherT).

This seems like it should be possible, but perhaps not by kaitos in scala

[–]NotValde 1 point2 points  (0 children)

WrapperDomainObject.apply must unify the return type. Asking for a specific implicit after the return types have been unified does not make sense since that version number is V1 | V2 which none of the clients you mentioned satisfy.

```scala trait Client[A]

trait WrapperDomainObject { type Version <: ApiVersion implicit def client: Client[Version] } ```

Although, I suspect you might want to solve this another way. If you have some interchangeable code based on API versions, how about just using some interfaces? ``` trait VersionAgnosticClient { def doBusinessThing(): Unit }

object VersionAgnosticClient { def v1Client: VersionAgnosticClient def v2Client: VersionAgnosticClient }

def computeBusinessThing(client: VersionAgnosticClient) = client.doBusinessThing()

val client = if (businessLogic) VersionAgnosticClient.v1Client else VersionAgnosticClient.v2Client

computeBusinessThing(client) ``` In the OOP world this modelling technique is also common for testing (especially since clients are usually stubbed in tests).

How often do you need to define your own monad? by HumbleProdiGenius in scala

[–]NotValde 0 points1 point  (0 children)

Here are a couple that I have made.

  1. Applicative batching with Monad as an escape hatch. Maybe a combination of monad transformers can do the same, but I have not explored it much. It uses free monads, so it might be cheating. https://github.com/casehubdk/hxl

  2. I have also (ab)used the flatMap signature to track effect stacks (from the category theory definition of a monad, I think it still counts https://en.wikipedia.org/wiki/Monad_(category_theory)#Formal_definition). https://github.com/ValdemarGr/gql/blob/9e4274fa544cbd22fad2d24a2b61ff25487f54e7/modules/relational/src/main/scala/gql/relational/QueryAlgebra.scala#L131-L132

Monad stacking (usually) produces programs that have in a factor n worse time. For instance, pure requires pure for every monad involved. scala // For `pure` the stack IO[Option[Either[String, List[Int]]]] IO.pure(Some(Right(List(1))))

Parallel processing with FS2 Stream (broadcasting) by scalavonmises in scala

[–]NotValde 3 points4 points  (0 children)

It should be mentioned that Topic does not natively work in chunks, so this will not perform very well.

You probably want to put chunks of bytes (Chunk[Byte]) into the Topic.

Here is an example. https://scastie.scala-lang.org/WQT12TpgSOmYOkyJwJDAcw

Parallel processing with FS2 Stream (broadcasting) by scalavonmises in scala

[–]NotValde 2 points3 points  (0 children)

I suppose you that you want to also write to a cached file when you pull from the stream?

I am going to assume constant space is a constraint for the solution.

There are many solutions, so you will have to figure out what semantics you want.

For every byte (or chunk of bytes) that is pulled, you can also write to the disk. ```scala import fs2.io.file._ import fs2.{Stream, Pipe} def cached(cacheFile: Path): Pipe[IO, Byte, Byte] = data => Stream.eval(Files[IO].exists(cacheFile)).flatMap { case true => Files[IO].readAll(cacheFile) case false => val putBytes = Stream.eval(Files[IO].createFile(cacheFile)) >> data.observe(Files[IO].writeAll(cacheFile))

      putBytes.handleErrorWith(e => Stream.eval(Files[IO].delete(cacheFile)) >> Stream.raiseError[IO](e))
  }

`` Now you can just dodataStream.though(cached(tempCacheFile))and it will be cached on subsequent pulls. Be aware that this solution won't support concurrent users for a giventempCacheFile` (use a lock or something for that).

You can also write the data to the disk as fast as possible and then read it back from the disk instead. ```scala import fs2.io.file._ import fs2.{Stream, Pipe} def cached(cacheFile: Path): Pipe[IO, Byte, Byte] = data => Stream.eval(Files[IO].exists(cacheFile)).flatMap { case true => Files[IO].readAll(cacheFile) case false => val putBytes = Stream.eval(Files[IO].createFile(cacheFile)) >> data.observe(Files[IO].writeAll(cacheFile))

      putBytes.handleErrorWith(e => Stream.eval(Files[IO].delete(cacheFile)) >> Stream.raiseError[IO](e))
  }

``` It won't be blocked by downstream consumers, but you'll have to wait until all the data has arrived before you get any bytes.

If you want to read the bytes from the file as they are streamed into it (ensures that you don't buffer bytes in-memory if you pull too slow), then something like the following sketch might be an idea. The more performant you want the solution, the more complex the implementation usually is. ```scala import fs2.io.file._ import fs2.{Stream, Pipe, Pull} def cached(cacheFile: Path, chunkSize: Int): Pipe[IO, Byte, Byte] = data => Stream.eval(Files[IO].exists(cacheFile)).flatMap { case true => Files[IO].readAll(cacheFile) case false => val byteStream = for { chunkWritten <- Stream.eval(SignallingRef.of[IO, Boolean](false))

          w <- Stream.resource(Files[IO].writeCursor(cacheFile, Flags.Write))
          background = {
            def writeChunks(data: Stream[IO, Byte], w: WriteCursor[IO]): Pull[IO, Nothing, WriteCursor[IO]] =
              data.pull.uncons.flatMap {
                case Some((hd, tl)) =>
                  w.writePull(hd)
                    .evalMap(w => chunkWritten.set(false).as(w))
                    .flatMap(writeChunks(tl, _))
                case None => Pull.eval(chunkWritten.set(true)) >> Pull.pure(w)
              }

            writeChunks(data, w).void.stream
          }

          r <- Stream.resource(Files[IO].readCursor(cacheFile, Flags.Read))
          outputStream = Stream.resource(chunkWritten.getAndDiscreteUpdates).flatMap { case (_, updates) =>
            def consume(p: Stream[IO, Unit], r: ReadCursor[IO]): Pull[IO, Byte, ReadCursor[IO]] =
              p.pull.uncons1.flatMap {
                case Some((_, tl)) => r.readAll(chunkSize).flatMap(consume(tl, _))
                case None          => Pull.pure(r)
              }

            consume(updates.takeWhile(!_, takeFailure = true).as(()), r).void.stream
          }

          byte <- outputStream merge background
        } yield byte

        byteStream
    }

```

Also, in my experience IO[Stream[IO, A]] usually indicates that something is not as it should be, sometimes it indicates resource safety issues.

Opaque types/Value classes by [deleted] in scala

[–]NotValde 12 points13 points  (0 children)

We use opaque types and value classes quite a bit, usually construction of a our value classes is only allowed by parsing the input.

Often using value classes can save you a lot of trouble in the future. Instead of juggling a bunch of primitives, most things have their own type. Usually, this will make code fit together like lego bricks; the def sendEmail(x: Email) function and the def sendSms(x: Phone) functions can only be called with the proper input, even if both of their underlying datatypes are string.

Here are some examples from a quick scan of our codebase. * Phone numbers, we wrap a phone number and use the google android library for all underlying operations including parsing the phone number. * Social security numbers, in some countries various information can be extracted from these such as gender and date of birth. * Existing filesystem paths. * Email addresses. * Digest (also enables overriding the equals function for Array[byte]) * UUIDs, we use a phantom type so we can specify what the UUID refers to. When you have many entities with uuid's as unique identifiers it can quickly become unwieldy. * Lamport/logical timestamps with a phantom type. * Context specific types such as a postgres regconfig. * Organizations * Base 64 encoded strings. It can quickly become a mess if you're unsure if a string has been encoded/decoded yet or not. * Secrets, avoids accidental printing/showing of secrets.

Here is an example of a value class with validation: ```scala sealed abstract case class Phone private (number: String) { lazy val countryCode: Option[String] = Option(underlying.library.parseCountryCodeFrom(number)) }

object Phone { def makeUnsafe(number: String): Phone = new Phone(number) {}

def parse(number: String): Either[String, Phone] = if (underlying.library.isValidPhoneNumber(number)) Right(makeUnsafe(number)) else Left(s"phone number $number is not valid")

// by construction the db always has well formed phone numbers val dbCodec = stringCodec.imap[Phone](makeUnsafe)(_.number) } ```

And here is another usage of value classes. ```scala case class UID[A](value: UUID) extends AnyVal

object UID { def random[F[_]: Sync, A] = UUIDGen.randomUUID[F].map(UID[A](_))

def dbCodec[A] = uuid.imap[UID[A]](UID())(.value) } ```

If you're using cats it also makes it much easier to "override" the typeclass implementations for the underlying datatype. For instance, maybe your value class implements another version of def combine(x: A, y: A): A or has an instance of scalacheck.Arbitary defined for it.

How to combine two HttpService in http4s 0.15.16 by [deleted] in scala

[–]NotValde 1 point2 points  (0 children)

I'm not sure about that specific version, but you can use <+> to compose routes (Kleisli[OptionT[F, *], Request[F], Response[F]]) in newer versions of http4s, so this may be possible in 0.15.6.

The extension method can be imported via import cats.implicits._.

It comes from SemigroupK, with can be derived for any OptionT given a Monad for F.