Posts in the “scala” category

ZIO ZLayer: A simple “Hello, world” example (dependency injection, services)

As a brief note today, here is some source code for a ZIO ZLayer application using Scala 3. In this code I use the ZLayer framework to handle some dependency injection for a small application. (Note that I don’t like to use the word “simple” when writing about computer programming, but I have tried to make this as simple as I can.)

I’ve commented the code below as multiple “parts” so you can see the thought process of creating an application that uses ZLayer. Basically the idea is that your application needs some sort of service — which might be like a database connection pool, HTTP framework, etc. — and then you make that service available to your application with ZLayer’s provideLayer function (or one of its other functions).

The ZLayer example

Given that small introduction, here’s my ZIO ZLayer example, with many notes shown in the comments inside the code:

Scala List class: 100+ method examples (map, filter, fold, reduce)

This page contains a large collection of examples of how to use the methods on the Scala List class.

Scala List class introduction

The List class is an immutable, linear, linked-list class. It’s very efficient when it makes sense for your algorithms to (a) prepend all new elements, (b) work with it in terms of its head and tail elements, and (c) use functional methods that traverse the list from beginning to end, such as filter, map, foldLeft, reduceLeft.

Scala: How to define a generic method parameter that must extend a base type (bounds)

In today’s installation of “how to have fun with Scala,” if you want to (a) define a Scala method that takes an input parameter, and (b) that parameter has a generic type, and (c) you further want to further declare that the parameter must extend some base type, then (d) use this “bounds” syntax:

def getName[A <: RequiredBaseType](a: A) = ???

This example can be read as, “The parameter a has the generic type A, and A must be a subtype of RequiredBaseType.”

A complete Scala bounds example

As a concrete example of how using bounds works, start with a simple base type, such as this Scala trait:

trait SentientBeing {
    def name: String
}

Next, extend that base trait with a few more traits:

trait AnimalWithLegs extends SentientBeing
trait TwoLeggedAnimal extends AnimalWithLegs
trait FourLeggedAnimal extends AnimalWithLegs

Then extend those with some concrete case classes:

case class Dog(name: String) extends FourLeggedAnimal
case class Person(name: String, age: Int) extends TwoLeggedAnimal
case class Snake(name: String) extends SentientBeing

Notice that Snake extends SentientBeing, but not AnimalWithLegs.

Now that you have all the types you need, define a method that takes a parameter that has a generic type that must extend some base type. To see how everything works, define it this way the first time:

def getName[A <: SentientBeing](a: A): String = a.name

Because the base type (or “super type”) is SentientBeing, all of these calls work just fine:

getName(Person("Fred", 20))
getName(Dog("Rover"))
getName(Snake("Noodles"))

(Copy and paste those into the Scala REPL if you want to verify they work as advertised.)

Now extend AnimalWithLegs

Next, change getName so the generic type A must be a subtype of AnimalWithLegs:

def getName[A <: AnimalWithLegs](a: A): String = a.name

Now, when you run the same three method calls again, you’ll see that the Snake example fails because it doesn’t extend AnimalWithLegs:

getName(Person("Fred", 20))
getName(Dog("Rover"))
getName(Snake("Noodles"))   //error

Here’s what the two sets of getName examples look like in the Scala REPL:

Show a Scala method with generic type parameter

(Right-click that image and select “View image” to see it larger.)

The Scala “type parameter bounds” error

As shown, the second Snake example results in this error message:

scala> getName(Snake("Noodles"))
<console>:15: error: inferred type arguments [Snake] do not conform to method getName's 
type parameter bounds [A <: AnimalWithLegs]
       getName(Snake("Noodles"))
       ^
<console>:15: error: type mismatch;
 found   : Snake
 required: A
       getName(Snake("Noodles"))
                    ^

This is because the type Snake does not extend AnimalWithLegs. (At least not in my world.)

Technical matters: ‘A’ has an “upper bound”

Technically what’s happening here is that I’m defining A with an “upper bound.” Bounds let you place restrictions on type parameters, and in this example I’m saying, “A must be a subtype of the type AnimalWithLegs”:

def getName[A <: AnimalWithLegs](a: A): String = a.name

More generally, this is how you say, “A must be a subtype of B”:

A <: B

I write more about this topic in, An introduction to Scala Types, so please see that article for a few more details.

A “bounds” video

If you’re interested in more information on this topic, see my free “Scala 3 Bounds” training video.

ZIO 2 Example: Making an HTTP GET request with a timeout, using sttp client

As a brief note today, here’s an example of making an HTTP GET request using ZIO 2 and the Scala sttp library. I also let the user specify a “timeout” value, so the request will timeout, rather than hanging.

As a very important note, this is a blocking approach, not a non-blocking approach.

ZIO 2 HTTP GET request with a timeout example

Here’s the source code and Scala 3 + ZIO 2 + sttp function:

ZIO/ZLayer FAQ: How do I create a very simple ZLayer with ZIO 2?

ZIO FAQ: How do I create a very simple ZLayer in a ZIO 2 application?

Solution

As a wee bit of background, the ZIO Zlayer approach provides several important purposes, including:

  • Dependency injection
  • Modularity and composability
  • Resource management
  • Testability
  • Separation of concerns
  • Type safety

How to clear/reset a Scala REPL session (without having to kill the session)

A cool feature of the Scala REPL is that you can reset/clear a REPL session. To do so, just issue the :reset command, like this:

scala> :reset
Resetting interpreter state.
Forgetting this session history:

Assuming that you already have at least a little history in your REPL session, the :reset command will show you everything that it dumps, so the full output looks more like this:

How to enter multiline commands (statements) into the Scala REPL

When you want to test a multiline command/statement in the Scala REPL, you can easily run into a problem where the REPL gets confused, or more accurately, it attempts to evaluate your statement too early.

As a simple example of this, imagine that you want to test the Scala "if" statement syntax. You begin typing your if statement normally, but when you hit [Enter] after your second line, you'll see that everything blows up:

With the right motivation, you might have discovered functional programming techniques yourself

As I mention in my free functional programming videos, if you had the desire to see your code as math, you might have discovered FP techniques yourself.

As an example, 20 years ago I couldn’t get my sysadmin to install a server-side spam filter at my consulting firm because he was always “too busy.”

So I wrote my own spam-filtering algorithm, and then someone with a CS degree looked at it and said, “That’s a Bayesian algorithm.” I had no idea what that was, I just knew that I was sick and tired of seeing spam all the time.

I later presented this solution at the 2004 Borland Conference (demonstrating how JBuilder helped at that time).

Scala 3 opaque types: How to create meaningful type names

This is an excerpt from the Scala Cookbook, 2nd Edition. This is Recipe 23.7, Creating Meaningful Scala Type Names with Opaque Types.

Problem

In keeping with practices like Domain-Driven Design (DDD), you want to give values that have simple types like String and Int more meaningful type names to make your code safer and easier to read.

Solution

In Scala 3, the solution is to use opaque types to create meaningful type names. For an example of the problem, when a customer orders something on an e-commerce website you may add it to a cart using the customerId and the productId:

ZIO 2: Passing a ZLayer value to an application, getting a return value, and handling possible errors

As a little note today, here’s an example ZIO 2 application where I do the following:

  • Pass a value to the ZIO application (named app) from run using a ZLayer
  • Use that ZLayer value in the application
  • Pass a result value from the application back to the run value
  • Use that value in run
  • Handle any possible errors in run with foldZIO
  • Show other ways to write the run value/function

ZIO/ZLayer example

Given that introduction, here’s the ZIO source code:

ZIO/ZLayer FAQ: How to use a Java Properties files with ZIO

ZIO/ZLayer FAQ: How do I use a Java Properties file with ZIO 2 and Scala?

Solution

You can use the zio-config library for things like this, but at the moment my preferred approach is to hand-code this ZLayer solution. Maybe that’s because I know how to work with a Java Properties file — i.e., how to read and load it — so I like to see those details.

Therefore, given this Java properties file named application.properties:

A ZIO ZLayer logging example (with Scala-CLI)

As a brief note today, and without much discussion, here’s a ZIO 2 ZLayer example I’ve been working on. The intent of the example is to show one possible way you can enable logging in a ZIO application using ZLayer.

ZIO ZLayer and logging example

As I mentioned, without much discussion, here’s the ZIO 2 source code: