<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Depa Reddy</title>
    <description>The latest articles on DEV Community by Depa Reddy (@depa_reddy_5e0e3025aa6eed).</description>
    <link>https://dev.to/depa_reddy_5e0e3025aa6eed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2746845%2F85dced2f-bbad-4617-bbd6-f1e125621e8b.png</url>
      <title>DEV Community: Depa Reddy</title>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/depa_reddy_5e0e3025aa6eed"/>
    <language>en</language>
    <item>
      <title>Demystifying Scala 3 Macros: A Deep Dive with Quoting and Splicing</title>
      <dc:creator>Depa Reddy</dc:creator>
      <pubDate>Sun, 07 Dec 2025 18:48:00 +0000</pubDate>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed/demystifying-scala-3-macros-a-deep-dive-with-quoting-and-splicing-4em7</link>
      <guid>https://dev.to/depa_reddy_5e0e3025aa6eed/demystifying-scala-3-macros-a-deep-dive-with-quoting-and-splicing-4em7</guid>
      <description>&lt;p&gt;Welcome to the world of compile-time metaprogramming in Scala 3! Macros can seem like magic, but they are built on a powerful and elegant system of Quoting and Splicing. Today, we're going to dissect a practical and elegant macro that converts any case class into a Map[String, Any]. By the end of this article, you'll understand not just what this macro does, but how it works, right down to the low-level reflection concepts that power it.&lt;/p&gt;

&lt;p&gt;Here is the code we will be exploring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.dev24.macros&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;scala.quoted.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;ToMapMacro&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The user-facing, inline method&lt;/span&gt;
  &lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toMap&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;toMapImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// The implementation that runs at compile time&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toMapImpl&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A:&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;])(&lt;/span&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="nc"&gt;Quotes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;quotes.reflect.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. Get the type and symbol of A&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;tpe&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;TypeRepr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;of&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;sym&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;tpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;typeSymbol&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Get the list of case class fields&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fields&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Symbol&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
      &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sym&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;isClassDef&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;sym&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;caseFields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toList&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nc"&gt;Nil&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. For each field, generate a quoted (String, Any) tuple&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;mapEntries&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;)]]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fieldNameExpr&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fieldAccess&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;asTerm&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fieldValueExpr&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;fieldAccess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;asExprOf&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;$fieldNameExpr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;$fieldValueExpr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Assemble the final Map from the list of tuples&lt;/span&gt;
    &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Varargs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapEntries&lt;/span&gt;&lt;span class="o"&gt;)}*)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down piece by piece.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1: The Gateway to Metaprogramming&lt;/strong&gt; - The &lt;strong&gt;inline&lt;/strong&gt; Method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toMap&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; 
&lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;toMapImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;'a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the method the user will call. It's designed to look and feel like a regular method, but it's anything but.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;extension [A]&lt;/strong&gt;: This is just modern Scala syntax to add a method to any type A. It's syntactic sugar and makes the call site clean: myCaseClass.toMap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inline a: A&lt;/strong&gt;: The inline keyword is the trigger. It tells the Scala compiler, "Do not execute this method at runtime. Instead, when you see a call to this method, replace it with the result of the code on the right-hand side during compilation."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;${ ... }&lt;/strong&gt;: This is the Splice operator. It's the bridge from the "normal" code world to the "macro" world. The code inside the splice is executed by the compiler as it builds your program.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;toMapImpl('a)&lt;/strong&gt;: This is the call to our macro implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;toMapImpl&lt;/strong&gt;: The function that will generate the code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;'a&lt;/strong&gt;: This is the Quote operator (an apostrophe). It takes   the value a and lifts it into the compiler's world as a representation of the code that produced a. This is not the runtime value of a; it is an Abstract Syntax Tree (AST) node representing the expression a. We call this a quoted expression. Its type is Expr[A]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In short: When the compiler sees person.toMap, it pauses compilation, calls toMapImpl with a quoted representation of the person expression, gets back a new piece of code (a quoted Map), and splices that new code directly into the program where person.toMap used to be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: The Engine Room **- **The Macro Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;toMapImpl&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A:&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;])(&lt;/span&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="nc"&gt;Quotes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the real work happens. This function runs inside the compiler during the compilation phase.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A: Type&lt;/strong&gt;: This is a Context Bound. It's a request for a Type[A] instance to be available. Type[A] is a "type tag." It's the quoted representation of the type A itself (e.g., Person, not an instance of Person). This is how the macro knows what class it's working with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;instance: Expr[A]&lt;/strong&gt;: This is the quoted expression we passed in with 'a. It's the AST for the value being converted (e.g., the AST for Person("Alice", 30)).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;(using Quotes)&lt;/strong&gt;: This is a Context Parameter. Quotes is the macro's toolbox. It provides access to all the reflection and metaprogramming utilities. It's the entry point to the compiler's internal APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;: Expr[Map[String, Any]]&lt;/strong&gt;: This is the return type. Crucially, the macro does not return a Map. It returns a quoted expression that, when compiled and run, will produce a Map. This is the fundamental contract of a macro: generate code, don't compute runtime values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Low-Level Reflection&lt;/strong&gt;: &lt;strong&gt;import quotes.reflect.&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;To do the heavy lifting of inspecting the class structure, we need to go deeper than the high-level &lt;strong&gt;Quotes&lt;/strong&gt; API provides. &lt;strong&gt;import quotes.reflect.&lt;/strong&gt;* gives us access to the compiler's core reflection types.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeRepr&lt;/strong&gt;: A rich, internal representation of a type. It's more detailed than Type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symbol&lt;/strong&gt;: The most fundamental concept. A Symbol is a unique name for any declaration in Scala: a class, a trait, an object, a method, a field, a type parameter, etc. Think of it as the ultimate "key" in the compiler's symbol table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Term&lt;/strong&gt;: A general representation of an expression or statement in the AST. An Expr is a type-safe wrapper around a Term.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Inspecting the Type&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;tpe&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;TypeRepr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;of&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;A&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;sym&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;tpe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;typeSymbol&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;TypeRepr.of[A]: We use our Type[A] evidence to get the full, rich TypeRepr for A. Represents a type (e.g., User, String, List[Int]). It's the "what is its structure?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This line is about getting a handle on the type itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1&lt;/strong&gt;: val tpe = TypeRepr.of[A]&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;[A]&lt;/strong&gt;: This is a type parameter. The code must be inside a context where A is known, such as a generic method (def myMethod[A]: ...) or a generic class (class MyClass[A]).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeRepr&lt;/strong&gt;: This is the central class in Scala 3's reflection API for representing types. A TypeRepr is the compiler's internal, rich description of a type. It can tell you everything about the type's structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.of[...]&lt;/strong&gt;: This is a summoning method. It asks the compiler: "Give me your internal TypeRepr object for the type I specify here." This operation happens entirely at compile time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What tpe contains&lt;/strong&gt;:&lt;br&gt;
&lt;strong&gt;If A is List[String]&lt;/strong&gt;, tpe is a TypeRepr that knows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its base type is scala.collection.immutable.List.&lt;/li&gt;
&lt;li&gt;It has one type argument, which is scala.Predef.String.&lt;/li&gt;
&lt;li&gt;It's a concrete, applied type (not a generic type constructor like List on its own).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If A is just Int, tpe is a TypeRepr that represents the scala.Int type.&lt;/p&gt;

&lt;p&gt;** tpe.typeSymbol**: From the type representation, we get its primary Symbol. If A is Person, sym is the Symbol for the Person class definition itself. Symbol Represents a declaration or name (e.g., the name of a class User, a method getName, or a field age). It's the "what is it called?" and "where was it defined?".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 2:&lt;/strong&gt; val sym = tpe.typeSymbol&lt;/p&gt;

&lt;p&gt;This line is about finding the definition or declaration that created the type.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tpe&lt;/strong&gt;: This is the TypeRepr we got from the first line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.typeSymbol&lt;/strong&gt;: This method is called on a TypeRepr. It navigates from the type to the symbol that declared it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symbol&lt;/strong&gt;: A Symbol in Scala 3 reflection represents a named declaration in your source code. This could be a class, trait, object, method, val, var, or type parameter. It's the "nameplate" of the entity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What&lt;/strong&gt; sym &lt;strong&gt;contains&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;If tpe represents List[String], then sym is the Symbol for the declaration of class List in the Scala library. It has forgotten about the [String] part.&lt;/p&gt;

&lt;p&gt;If tpe represents a case class User(name: String), then sym is the Symbol for class User&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Finding the Fields&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fields&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Symbol&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sym&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;isClassDef&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;sym&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;caseFields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toList&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nc"&gt;Nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;sym.isClassDef&lt;/strong&gt;: We check if the symbol represents a class. This is a safety measure to ensure we don't try to get fields from a type like Int or String.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sym.caseFields&lt;/strong&gt;: This is a powerful helper method on a class Symbol. It returns a List[Symbol] representing the public constructor parameters of the case class. For case class Person(name: String, age: Int), this will be a list containing the symbols for name and age.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Generating the Map Entries (The Core Loop)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the heart of the macro, where quoting and splicing dance together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;mapEntries&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;, &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;)]]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fieldNameExpr&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fieldAccess&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Select&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;asTerm&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;fieldValueExpr&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;fieldAccess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;asExprOf&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;$fieldNameExpr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;$fieldValueExpr&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are iterating over each field Symbol to create a quoted tuple ("fieldName", fieldValue).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;val fieldNameExpr = Expr(field.name):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;field.name&lt;/strong&gt; gives us the actual string name of the field (e.g., "name").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expr(...)&lt;/strong&gt; is a helper that quotes a value. It takes a runtime value (the string "name") and creates a quoted expression representing that value's literal code. So Expr("name") produces the AST for the string literal "name".&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;val fieldAccess = Select(instance.asTerm, field)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is pure, low-level AST construction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;instance.asTerm&lt;/strong&gt;: We unwrap our type-safe Expr[A] to get the raw  Term AST node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Select(..., ...)&lt;/strong&gt;: This is a constructor for a field access AST node. It's equivalent to writing the code instance.field. The first argument is the "qualifier" (the object we're accessing the field on), and the second is the Symbol of the field to access. This creates the AST for person.name.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;val fieldValueExpr = fieldAccess.asExprOf[Any]&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We take the raw Term AST for person.name and wrap it back up into a type-safe Expr. We cast it to Any because a Map[String, Any] can hold any value type.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;{ ($fieldNameExpr, $fieldValueExpr) }&lt;/strong&gt;: This is the  masterpiece.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; The outer &lt;strong&gt;'{ ... }&lt;/strong&gt; is a Quote. It means: "Do not execute the code inside me now. Instead, construct an AST representing the code inside me."&lt;/li&gt;
&lt;li&gt;The inner &lt;strong&gt;$fieldNameExpr&lt;/strong&gt; and &lt;strong&gt;$fieldValueExpr&lt;/strong&gt; are &lt;strong&gt;Splices&lt;/strong&gt;. They mean: "Take the quoted expression I have in this variable and splice it into the code I am currently quoting."&lt;/li&gt;
&lt;li&gt; So, if &lt;strong&gt;fieldNameExpr&lt;/strong&gt; is the AST for "&lt;strong&gt;name&lt;/strong&gt;" and &lt;strong&gt;fieldValueExpr&lt;/strong&gt; is the AST for &lt;strong&gt;person.name&lt;/strong&gt;, this single line builds the AST for the tuple expression ("name", person.name).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The map function returns a List[Expr[(String, Any)]], which is a list of AST nodes, one for each (key, value) pair in our desired map.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Assembling the Final Map&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Varargs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapEntries&lt;/span&gt;&lt;span class="o"&gt;)}*)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the final step, where we assemble all the tuple ASTs into a single Map AST.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;'{ ... }&lt;/strong&gt;: Once again, a Quote to say "generate the code for..."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map(...)&lt;/strong&gt;: We're generating a call to the Map.apply factory method.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;${Varargs(mapEntries)}&lt;/strong&gt;*: This is a special splice.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;mapEntries&lt;/strong&gt; is our &lt;strong&gt;List[Expr[(String, Any)]]&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Varargs(...)&lt;/strong&gt; is a helper that takes a list of quoted expressions and prepares them to be used as a variable argument list. It bundles them into a single &lt;strong&gt;Expr[Seq[T]]&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;splice&lt;/strong&gt; ${...} injects this generated sequence of expressions into the &lt;strong&gt;Map&lt;/strong&gt; call.&lt;/li&gt;
&lt;li&gt;The ***** is part of the generated code, not the macro code. It's the syntax for splatting a sequence into varargs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So, this final line generates the complete AST for: Map(("name", person.name), ("age", person.age), ...).&lt;/p&gt;

&lt;p&gt;Putting It All Together: A Full Example&lt;/p&gt;

&lt;p&gt;Let's trace &lt;strong&gt;Person("Alice", 30).toMap&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Call Site&lt;/strong&gt;: The compiler sees &lt;strong&gt;Person("Alice", 30).toMap&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline Invocation&lt;/strong&gt;: Because toMap is inline, it calls toMapImpl.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Parameters&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;instance is the quoted code &lt;strong&gt;'{ Person("Alice", 30) }&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A is Person.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Inside &lt;strong&gt;toMapImpl&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fields becomes a list of the Symbols for name and age.&lt;/li&gt;
&lt;li&gt;For name:

&lt;ul&gt;
&lt;li&gt;fieldNameExpr becomes &lt;strong&gt;'{ "name" }&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;fieldAccess becomes the AST for &lt;strong&gt;Select(Person("Alice", 30), name_symbol)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;fieldValueExpr becomes &lt;strong&gt;'{ Person("Alice", 30).name }&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The map produces the quoted tuple &lt;strong&gt;'{ ("name", Person("Alice", 30).name) }&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;For age:

&lt;ul&gt;
&lt;li&gt;The map produces the quoted tuple &lt;strong&gt;'{ ("age", Person("Alice", 30).age) }&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;&lt;p&gt;mapEntries is now a list containing these two quoted tuples. &lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Final Code Generation&lt;/strong&gt;: The last line '{ &lt;strong&gt;Map(${Varargs(mapEntries)}*) }&lt;/strong&gt; produces the final quoted code:&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;'{ Map(("name", Person("Alice", 30).name), ("age", Person("Alice", 30).age)) }&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Splicing Back&lt;/strong&gt;: The compiler takes this result and splices it back into the user's code, replacing the original &lt;strong&gt;.toMap&lt;/strong&gt; call.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Final Compiled Code&lt;/strong&gt;: The program now effectively contains:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Map(("name", "Alice"), ("age", 30))&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The magic is complete. The boilerplate is gone, the runtime overhead is zero, and the code is perfectly type-safe.&lt;/p&gt;

&lt;p&gt;the full source can be found in below gist:&lt;br&gt;
&lt;a href="https://gist.github.com/depareddy/06b9f12afc73de3bce71a72bee4d44eb" rel="noopener noreferrer"&gt;https://gist.github.com/depareddy/06b9f12afc73de3bce71a72bee4d44eb&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deep Dive into Scala 3 Macros: Building a Custom String Interpolator</title>
      <dc:creator>Depa Reddy</dc:creator>
      <pubDate>Sun, 02 Nov 2025 13:12:00 +0000</pubDate>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed/deep-dive-into-scala-3-macros-building-a-custom-string-interpolator-354j</link>
      <guid>https://dev.to/depa_reddy_5e0e3025aa6eed/deep-dive-into-scala-3-macros-building-a-custom-string-interpolator-354j</guid>
      <description>&lt;p&gt;This blog post explores the powerful macro system in Scala 3 through a practical example: a custom string interpolator that adds debug information to interpolated values. We'll break down the code and explain the concepts behind it, giving you the knowledge to create your own macros.&lt;/p&gt;

&lt;p&gt;Before we dissect the code, let's cover the basics. If macros sound intimidating, think of them as "meta-programming" tools that let your code think about itself. In Scala 3, macros use Tasty, Scala's internal representation (short for "Typed Abstract Syntax Trees"—a blueprint of your code that the compiler understands and manipulates).&lt;/p&gt;

&lt;p&gt;What are macros? Normal code runs when your program executes (runtime). Macro code runs during compilation (when Scala turns your .scala files into runnable bytecode). They can analyze your code, change it, or generate new code on the fly. For example, a macro might see t"Hello $name" and rewrite it to optimized bytecode before the program starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction to String Interpolation in Scala&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;String interpolation in Scala allows embedding expressions directly into string literals. Scala 3 provides several built-in interpolators:&lt;/p&gt;

&lt;p&gt;s"Hello $name": Simple interpolation&lt;br&gt;
f"Hello $name%s": Formatted interpolation&lt;br&gt;
raw"Hello\n$name": Raw interpolation&lt;br&gt;
When you write s"Hello $name", the compiler transforms it into:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;StringContext("Hello ", "").s(name)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This transformation opens the door to custom interpolators, which we'll explore next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the Code Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's break down our custom interpolator code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.dev24.macros&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;scala.quoted.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;scala.util.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We start with the necessary imports, particularly scala.quoted.* which is essential for working with macros in Scala 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime Helper Methods&lt;/strong&gt;&lt;br&gt;
Our implementation includes two runtime helper methods:&lt;/p&gt;

&lt;p&gt;Runtime Helper Methods&lt;br&gt;
Our implementation includes two runtime helper methods:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;buildTaggedString&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;taggedArgs&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"[DEBUG] ${arg.toString}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;length&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;taggedArgs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This method:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Takes an array of string parts (the literal parts of the interpolated string)&lt;/li&gt;
&lt;li&gt;Takes variable arguments (the expressions to be interpolated)&lt;/li&gt;
&lt;li&gt;Wraps each argument with "[DEBUG]" prefix&lt;/li&gt;
&lt;li&gt;Constructs the final string by alternating parts and tagged arguments&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;buildTaggedStringFromContext&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedStringFromContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;StringContext&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;taggedArgs&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"[DEBUG] ${arg.toString}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;sc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;toArray&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;
  &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;until&lt;/span&gt; &lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;length&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;taggedArgs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is similar to the previous method but:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Takes a StringContext directly (which contains the parts)&lt;/li&gt;
&lt;li&gt;Converts parts to uppercase&lt;/li&gt;
&lt;li&gt;Used as a fallback when compile-time analysis isn't possible&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Extension Method&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nf"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;StringContext&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;transparent&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;tMacro&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;'sc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;'args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
 scala&lt;br&gt;
This defines an extension method on StringContext:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;transparent inline&lt;/code&gt; indicates this is an inline method that will be expanded at compile time&lt;/li&gt;
&lt;li&gt;The method takes variable arguments&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;${ tMacro('sc, 'args) }&lt;/code&gt; is the macro expansion syntax, calling the tMacro function with the StringContext and arguments as quoted expressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Macro Implementation&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tMacro&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;StringContext&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="o"&gt;]])(&lt;/span&gt;&lt;span class="n"&gt;using&lt;/span&gt; &lt;span class="nc"&gt;Quotes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;quotes.reflect.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;

  &lt;span class="n"&gt;sc&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;StringContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Varargs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partExprs&lt;/span&gt;&lt;span class="o"&gt;)}*)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// Try to extract literal parts&lt;/span&gt;
      &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;partsOpt&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;partExprs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nv"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;asTerm&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Literal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StringConstant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// If all parts are literal and args are Varargs, do compile-time path&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;partsOpt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;forall&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;isDefined&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Varargs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argExprs&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;partsOpt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;processed&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;processedPartsExpr&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ofSeq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;processed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
            &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$processedPartsExpr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toArray&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Varargs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argExprs&lt;/span&gt;&lt;span class="o"&gt;)}*)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="c1"&gt;// args not Varargs at compile time -&amp;gt; runtime fallback&lt;/span&gt;
            &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedStringFromContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;$sc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="c1"&gt;// parts not all literals -&amp;gt; runtime fallback&lt;/span&gt;
        &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedStringFromContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;$sc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// sc not a StringContext literal -&amp;gt; runtime fallback&lt;/span&gt;
      &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedStringFromContext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;$sc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is the core macro implementation. Let's break it down:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function Signature&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes an &lt;code&gt;Expr[StringContext]&lt;/code&gt; (quoted expression of StringContext)&lt;/li&gt;
&lt;li&gt;Takes an &lt;code&gt;Expr[Seq[Any]]&lt;/code&gt; (quoted expression of the arguments)&lt;/li&gt;
&lt;li&gt;Returns an &lt;code&gt;Expr[String]&lt;/code&gt; (quoted expression of the result)&lt;/li&gt;
&lt;li&gt;Requires a &lt;code&gt;Quotes&lt;/code&gt; context for macro operations&lt;/li&gt;
&lt;li&gt;Pattern Matching on StringContext&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;case '{ StringContext(${Varargs(partExprs)}*) } =&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This matches a StringContext with varargs of part expressions, extracting the literal parts of the interpolated string.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extracting Literal Parts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;partsOpt&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Seq&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;partExprs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nv"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;asTerm&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Literal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StringConstant&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For each part expression, it tries to extract the literal string value:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;expr.asTerm&lt;/code&gt; converts the expression to a term&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Literal(StringConstant(str))&lt;/code&gt; matches a literal string constant&lt;/p&gt;

&lt;p&gt;If not a literal, returns None&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compile-time Path&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If all parts are literals and args are varargs, it processes at compile time:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;parts&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;partsOpt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;processed&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;processedPartsExpr&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;ofSeq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;processed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Expr&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;buildTaggedString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$processedPartsExpr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toArray&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Varargs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argExprs&lt;/span&gt;&lt;span class="o"&gt;)}*)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Converts parts to uppercase&lt;/li&gt;
&lt;li&gt;Creates a new expression that calls buildTaggedString with the processed parts and original arguments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Runtime Fallback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If parts aren't all literals or args aren't varargs, it falls back to runtime processing:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;'{ buildTaggedStringFromContext($sc, $args) }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Concepts in Scala 3 Macros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quotes and Splices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quotes and splices are the fundamental building blocks of Scala 3 macros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quotes &lt;code&gt;('{...})&lt;/code&gt;:&lt;/strong&gt; Capture code as data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Splices &lt;code&gt;(${...})&lt;/code&gt;:&lt;/strong&gt; Insert code into quotes&lt;/li&gt;
&lt;li&gt;In our example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="n"&gt;transparent&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;$&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;tMacro&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;'sc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;'args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
 scala&lt;br&gt;
The &lt;code&gt;'sc&lt;/code&gt; and &lt;code&gt;'args&lt;/code&gt; are quotes, and &lt;code&gt;${ tMacro(...) }&lt;/code&gt; is a splice that inserts the result of the macro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparent Inline Methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;transparent inline methods are a key feature for macros in Scala 3:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;inline:&lt;/strong&gt; The method call is replaced with the method body at compile time&lt;br&gt;
&lt;strong&gt;transparent:&lt;/strong&gt; The compiler can see through the method to infer more precise types&lt;/p&gt;

&lt;p&gt;This enables the macro to generate code that's type-checked in the context where it's used.&lt;/p&gt;

&lt;p&gt;Compile-time vs Runtime Processing&lt;/p&gt;

&lt;p&gt;Doing work at compile time has several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; The work is done once during compilation, not every time the code runs&lt;/li&gt;
&lt;li&gt;**Type safety: **Errors can be caught at compile time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimization:&lt;/strong&gt; The compiler can optimize the generated code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our example, when the string parts are known at compile time, we can process them immediately and generate optimized code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;LoggerExample&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.dev24.macros.CustomInterpolator._&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Alice"&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;age&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="s"&gt;"Hello $name, you are $age years old!"&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This demonstrates using the custom interpolator:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Imports the interpolator&lt;/li&gt;
&lt;li&gt;Defines some variables&lt;/li&gt;
&lt;li&gt;Uses the t interpolator to create a tagged string&lt;/li&gt;
&lt;li&gt;Prints the result&lt;/li&gt;
&lt;li&gt;The output would be:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;HELLO [DEBUG] Alice, YOU ARE [DEBUG] 30 YEARS OLD!&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical Applications of Custom Interpolators and Macros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Custom interpolators with macros have many practical applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Type-safe SQL:&lt;/strong&gt; Prevent SQL injection by validating queries at compile time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration:&lt;/strong&gt; Validate configuration files at compile time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging:&lt;/strong&gt; Add metadata to log messages automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization:&lt;/strong&gt; Validate that all translation keys exist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code generation:&lt;/strong&gt; Generate boilerplate code based on annotations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our example demonstrates a logging interpolator that adds debug tags to interpolated values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This code showcases the power of Scala 3's macro system through a custom string interpolator. It demonstrates how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define an extension method on StringContext&lt;/li&gt;
&lt;li&gt;Implement a macro that analyzes code at compile time&lt;/li&gt;
&lt;li&gt;Fall back to runtime processing when necessary&lt;/li&gt;
&lt;li&gt;Generate optimized code when possible&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The macro system in Scala 3 is more approachable and safer than in Scala 2, making it a powerful tool for metaprogramming and code generation. By understanding these concepts, you can create your own macros to optimize your code, improve type safety, and reduce boilerplate.&lt;/p&gt;

&lt;p&gt;Whether you're building a type-safe DSL, optimizing performance-critical code, or simply reducing boilerplate, Scala 3 macros provide a powerful and elegant solution.&lt;/p&gt;

&lt;p&gt;full source code can be found here:&lt;br&gt;


&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





</description>
      <category>computerscience</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Blog Post: Demystifying ZIO's Dependency Injection: A Practical Guide</title>
      <dc:creator>Depa Reddy</dc:creator>
      <pubDate>Sat, 01 Nov 2025 14:58:13 +0000</pubDate>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed/blog-post-demystifying-zios-dependency-injection-a-practical-guide-5c1g</link>
      <guid>https://dev.to/depa_reddy_5e0e3025aa6eed/blog-post-demystifying-zios-dependency-injection-a-practical-guide-5c1g</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction: The Problem of "Wiring" an Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In any non-trivial application, different parts need to talk to each other. A UserService might need a Database connection and an Emailer. A Database might need a Configuration object. This network of dependencies is often called "the application graph" or "the wiring."&lt;/p&gt;

&lt;p&gt;How do we manage this?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual new-ing?&lt;/strong&gt; new UserService(new Database(new Config()), new Emailer()). This gets messy fast and is hard to change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Framework like Spring?&lt;/strong&gt; This uses reflection and can be "magical," but sometimes you want compile-time guarantees and a more functional approach.
This is where ZIO shines. ZIO provides a powerful, purely functional, and compile-time safe way to manage dependencies using a feature called ZIO Layers. In this post, we'll build a simple application to demonstrate how it works.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;**The Goal: **A Simple User Registration Flow&lt;br&gt;
Our application will do one thing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receive a User.&lt;/li&gt;
&lt;li&gt;"Insert" that user into a "database" (we'll just print to the console).&lt;/li&gt;
&lt;li&gt;Send a notification email to that user (again, just printing to the console).
Let's look at the code and unpack the concepts piece by piece.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Part 1: The Building Blocks - Our Domain Models&lt;/strong&gt;&lt;br&gt;
First, we need some simple data structures. These are just plain Scala case classes with no ZIO-specific magic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In package com.dev24&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;User:&lt;/strong&gt; Represents a user in our system.&lt;br&gt;
&lt;strong&gt;Config:&lt;/strong&gt; Represents configuration data. Here, it just holds the name of our database table.&lt;br&gt;
These are our pure data models. They are simple, immutable, and easy to understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: Defining Capabilities with traits (The Service Interfaces)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In ZIO, a "service" is defined by its public API, which is typically a trait. This trait describes what a service can do, not how it does it. This separation is key for modularity and testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The UserEmailer Service&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In package com.dev24&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;

&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UserEmailer&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="kt"&gt;notify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;user:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;message:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Console&lt;/span&gt;, &lt;span class="kt"&gt;IOException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's dissect the notify method signature: ZIO[Console, IOException, Unit]. This is a ZIO effect, and its type parameters are its superpower:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;R (Requirement Type): Console&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is the dependency. It means that to execute this notify     effect, we need an implementation of the Console service available in our environment. Console is a built-in ZIO service for 
interacting with... well, the console.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;E (Error Type): IOException&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is the type of error that can fail the effect. If something goes wrong while trying to print, it might result in an IOException.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A (Success Type): Unit&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is the type of the value returned on success. We're just performing a side-effect (printing), so we don't need to return a meaningful value. Unit signifies "no value."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, notify is a description of a computation that says: "To run me, you need to give me a Console. I might fail with an IOException, and if I succeed, I'll give you nothing (Unit)."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The UserDb Service&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In package com.dev24&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.io.IOException&lt;/span&gt;

&lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;UserDb&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="kt"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;user:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Config&lt;/span&gt; &lt;span class="kt"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;Console&lt;/span&gt; &lt;span class="kt"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;UserEmailer&lt;/span&gt;, &lt;span class="kt"&gt;IOException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is where it gets more interesting. Look at the R type: Config &amp;amp; Console &amp;amp; UserEmailer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &amp;amp; (Intersection Type): This means the insert method requires all three of these services to be present in the environment to run. It needs the Config to get the table name, the Console to print the "insert" message, and the UserEmailer to send the notification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the heart of ZIO's dependency management. Dependencies are declared explicitly in the function signature, making them impossible to forget at compile time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: Creating Implementations with ZLayer (The Blueprints)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A trait is just an interface. We need concrete implementations. In ZIO, an implementation of a service is provided by a ZLayer.&lt;/p&gt;

&lt;p&gt;Think of a ZLayer as a recipe or a blueprint for building a service. It describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What service it builds (the "output").&lt;/li&gt;
&lt;li&gt;What services it needs to build it (the "input" or dependencies).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The UserEmailer.live Layer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;UserEmailer&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;
  &lt;span class="kt"&gt;lazy&lt;/span&gt; &lt;span class="kt"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;live:&lt;/span&gt; &lt;span class="kt"&gt;ULayer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UserEmailer&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
    &lt;span class="nv"&gt;ZLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;succeed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;new:&lt;/span&gt;
        &lt;span class="kt"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="kt"&gt;notify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;user:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;message:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Console&lt;/span&gt;, &lt;span class="kt"&gt;IOException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
          &lt;span class="nv"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;serviceWithZIO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;printLine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"[User emailer] Sending '$message' to ${user.email}"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;object UserEmailer:&lt;/strong&gt; We use a companion object to hold the implementations of our service. This is a common Scala pattern.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;live:&lt;/strong&gt; ULayer[UserEmailer]:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;live&lt;/strong&gt; is a conventional name for the production implementation of a service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ULayer[UserEmailer]&lt;/strong&gt; is the type. Layer[R, A] means "a layer that requires R to build A". ULayer[A] is just an alias for Layer[Any, A], meaning this layer has no dependencies. It can build a UserEmailer out of thin air.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ZLayer.succeed(...):&lt;/strong&gt; This is the simplest way to create a layer. It takes a pre-built instance of your service and wraps it in a layer. Since our UserEmailer doesn't need any complex setup, this is perfect.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;object UserEmailer:&lt;/strong&gt; We use a companion object to hold the implementations of our service. This is a common Scala pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;live:&lt;/strong&gt; ULayer[UserEmailer]:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;live&lt;/strong&gt; is a conventional name for the production implementation of a service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ULayer[UserEmailer]&lt;/strong&gt; is the type. Layer[R, A] means "a layer that requires R to build A". ULayer[A] is just an alias for Layer[Any, A], meaning this layer has no dependencies. It can build a UserEmailer out of thin air.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ZLayer.succeed(...):&lt;/strong&gt; This is the simplest way to create a layer. It takes a pre-built instance of your service and wraps it in a layer. Since our UserEmailer doesn't need any complex setup, this is perfect.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;new: ...:&lt;/strong&gt; We are creating an anonymous class that implements the UserEmailer trait.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ZIO.serviceWithZIO(_.printLine(...)):&lt;/strong&gt; This is a ZIO helper. &lt;br&gt;
It's shorthand for : Get the Console service from the environment (ZIO.service[Console]).Use its printLine method.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result of printLine is a ZIO[..., IOException, Unit], which is exactly what our notify method needs to return. We are creating an anonymous class that implements the UserEmailer trait.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ZIO.serviceWithZIO(_.printLine(...)): This is a ZIO helper. It's shorthand for:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1.Get the Console service from the environment (ZIO.service[Console]).&lt;br&gt;
 2.Use its printLine method.&lt;br&gt;
 3.The result of printLine is a ZIO[..., IOException, Unit], which is exactly what our notify method needs to return.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The UserDb.live Layer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In package com.dev24&lt;/span&gt;
&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;UserDb&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;
  &lt;span class="kt"&gt;lazy&lt;/span&gt; &lt;span class="kt"&gt;val&lt;/span&gt; &lt;span class="kt"&gt;live:&lt;/span&gt; &lt;span class="kt"&gt;ULayer&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UserDb&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;// Wait, no dependencies? We'll see...&lt;/span&gt;
    &lt;span class="nv"&gt;ZLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;succeed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;new:&lt;/span&gt;
        &lt;span class="kt"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="kt"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;user:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Config&lt;/span&gt; &lt;span class="kt"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;Console&lt;/span&gt; &lt;span class="kt"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;UserEmailer&lt;/span&gt;, &lt;span class="kt"&gt;IOException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
          &lt;span class="k"&gt;for&lt;/span&gt;
            &lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;environmentWith&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tableName&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt;
              &lt;span class="nv"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;serviceWithZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Console&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;printLine&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="s"&gt;"[Database] insert into $tableName values ('${user.email}')"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;_&lt;/span&gt; &lt;span class="k"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nv"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;serviceWithZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UserEmailer&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;notify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Message"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
          &lt;span class="nf"&gt;yield&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This looks similar, but let's focus on the implementation of &lt;strong&gt;insert.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;for { ... } yield ():&lt;/strong&gt; This is ZIO's version of a for-comprehension, used to sequence effects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;tableName &amp;lt;- ZIO.environmentWith&lt;a href="//_.get.tableName"&gt;Config&lt;/a&gt;:&lt;/strong&gt; This is another way to access a service from the environment. It pulls out the entire Config object and lets us access its tableName field.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;_ &amp;lt;- ZIO.serviceWithZIO&lt;a href="//_.notify(user,"&gt;UserEmailer&lt;/a&gt;):&lt;/strong&gt; Here, we are using another service! We get the UserEmailer from the environment and call its notify method.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Crucial Point:&lt;/strong&gt; Notice that UserDb.live is also a ULayer[UserDb]. This seems contradictory, right? The insert method requires dependencies, but the UserDb layer itself doesn't.&lt;/p&gt;

&lt;p&gt;This is a key concept: &lt;strong&gt;A layer's dependencies are for its construction, not for its usage.&lt;/strong&gt;&lt;br&gt;
Creating a UserDb instance (the new part) doesn't require a Config or Console. But calling methods on that instance does. The dependencies are deferred to the method calls, which is exactly what we want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 4: Assembling and Running the Application (Main)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we have all the pieces: our interfaces (traits) and our blueprints (ZLayers). The final step is to build the application and run it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In package com.dev24&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;zio.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="k"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ZIOAppDefault&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt;

  &lt;span class="c1"&gt;// 1. Define the user we want to insert&lt;/span&gt;
  &lt;span class="k"&gt;lazy&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;kamil&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"d@dev24.in"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// 2. Define the main logic of our application&lt;/span&gt;
  &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;appLogic&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UserDb&lt;/span&gt;, &lt;span class="kt"&gt;IOException&lt;/span&gt;, &lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
    &lt;span class="nv"&gt;ZIO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;serviceWithZIO&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UserDb&lt;/span&gt;&lt;span class="o"&gt;](&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;insert&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kamil&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;

  &lt;span class="c1"&gt;// 3. Assemble the environment (the wiring)&lt;/span&gt;
  &lt;span class="k"&gt;lazy&lt;/span&gt; &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="nv"&gt;env&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
    &lt;span class="nv"&gt;ZLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;succeed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConsoleLive&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="c1"&gt;// Provide the live Console implementation&lt;/span&gt;
    &lt;span class="nv"&gt;UserEmailer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;live&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;           &lt;span class="c1"&gt;// Provide our UserEmailer implementation&lt;/span&gt;
    &lt;span class="nv"&gt;UserDb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;live&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;                &lt;span class="c1"&gt;// Provide our UserDb implementation&lt;/span&gt;
    &lt;span class="nv"&gt;ZLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;succeed&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"table-x"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// Provide our Config instance&lt;/span&gt;

  &lt;span class="c1"&gt;// 4. Run the logic with the provided environment&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="k"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt;
    &lt;span class="nv"&gt;appLogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;provideLayer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's break down the Main object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.appLogic:&lt;/strong&gt; This is the core business logic of our application, described as a ZIO effect. It says: "I need a UserDb service, and I will call its insert method with kamil." Its type is ZIO[UserDb, IOException, Unit], meaning it requires UserDb and can fail with IOException.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.env:&lt;/strong&gt; This is where the magic happens. We are building our complete application environment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;** ZLayer.succeed(ConsoleLive):** Console is a special ZIO service. We need to provide its "live" implementation, which actually interacts with the system console.&lt;/li&gt;
&lt;li&gt;** ZLayer.succeed(Config("table-x")):** We create a layer from our simple Config case class instance.&lt;/li&gt;
&lt;li&gt;** ++ (The Horizontal Composition Operator):** This operator combines layers. It's like stacking blueprints. It tells ZIO: "Here are all the services available in my application." ZIO is smart enough to analyze the dependencies and figure out the correct construction order. For example, it knows that UserDb needs Config, so it will ensure Config is built before UserDb.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3.run:&lt;/strong&gt; Task[Unit]: This is the entry point for our ZIOAppDefault.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;appLogic.provideLayer(env):&lt;/strong&gt; This is the final, crucial step. We take our appLogic (which needs a UserDb) and we give it a complete blueprint (env) for building one.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;What happens here?&lt;/strong&gt; ZIO analyzes appLogic and sees it needs UserDb. It looks at env and finds the UserDb.live layer. It then builds the UserDb service. While building, it sees that the methods on UserDb need Config, Console, and UserEmailer. It finds those in the env as well. It builds everything, wires it all together, and finally executes the insert method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you run this, the output will be:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Database] insert into table-x values ('d@dev24.in')
[User emailer] Sending 'Message' to d@dev24.in

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Conclusion: Why This Approach is Powerful&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type-Safe Dependency Injection:&lt;/strong&gt; The Scala compiler guarantees that all dependencies are met. If you forget to provide Config in your env, your code will not compile. No more runtime &lt;br&gt;
NullPointerExceptions from missing dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testability:&lt;/strong&gt; This is a massive win. To test UserDb, you can provide a mock UserEmailer layer that doesn't actually send emails. You can provide a fake Config. Your UserDb code doesn't change at all; you just give it a different environment to run in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modularity and Reusability:&lt;/strong&gt; Services are completely decoupled. UserEmailer has no idea UserDb exists. You can reuse UserEmailer in any other part of your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explicitness:&lt;/strong&gt; There is no magic. Every dependency a function needs is declared right in its type signature. The code is self-documenting.&lt;/p&gt;

&lt;p&gt;This simple example demonstrates the foundational pattern for building robust, modular, and testable applications with ZIO. You define capabilities with traits, provide implementations with ZLayer, and wire them all together at the application's entry point.&lt;/p&gt;

&lt;p&gt;full source code can be found  below &lt;br&gt;


&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;





</description>
      <category>architecture</category>
      <category>designpatterns</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>State Monad</title>
      <dc:creator>Depa Reddy</dc:creator>
      <pubDate>Sun, 20 Jul 2025 09:25:52 +0000</pubDate>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed/state-monad-2ic4</link>
      <guid>https://dev.to/depa_reddy_5e0e3025aa6eed/state-monad-2ic4</guid>
      <description>&lt;p&gt;this below article assume some prior knowledge in  scala and monads.&lt;/p&gt;

&lt;p&gt;The State Monad is a concept from functional programming that allows for stateful computations to be represented in a pure functional way&lt;/p&gt;

&lt;p&gt;The State Monad addresses this challenge by allowing functions to carry state along with them. &lt;/p&gt;

&lt;p&gt;The key idea is to represent state as a function that takes an initial state and returns a new state along with a result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Concepts of the State Monad&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;State Representation: *&lt;/em&gt;&lt;br&gt;
The State Monad represents a computation that carries some state. &lt;br&gt;
It can be thought of as a function that takes an initial state and returns a value along with a new state.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Type Signature: *&lt;/em&gt;&lt;br&gt;
The type signature of a State Monad can be represented as State s,a = s -&amp;gt; (a,s):  Here s  is the type of the state, and a is the type of the result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Operations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;get: Retrieves the current state.&lt;br&gt;
put: Updates the state to a new value.&lt;br&gt;
modify: Applies a function to the current state to produce a new state.&lt;br&gt;
Composing State Computations: The State Monad allows for the composition of stateful computations using the flatMap (or bind) operation. This enables chaining multiple stateful operations together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. State Monad Definition&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;case class State[S, A](run: S =&amp;gt; (S, A)) {
  // Execute the state computation and return the final state
  def exec(s: S): S = run(s)._1

  // Evaluate the state computation and return the result
  def eval(s: S): A = run(s)._2
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Case Class: State is defined as a case class that takes two type parameters: S (the type of the state) and A (the type of the result).&lt;/p&gt;

&lt;p&gt;Run Method: The run method is a function that takes an initial state of type S and returns a tuple containing the new state of type S and a result of type A.&lt;/p&gt;

&lt;p&gt;exec Method: This method executes the state computation and returns the final state after running the computation.&lt;/p&gt;

&lt;p&gt;eval Method: This method evaluates the state computation and returns the result of type A.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Companion Object for State&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object State {
  // Create a State that replaces the current state with a new state
  def put[S](ns: S): State[S, Unit] = State(s =&amp;gt; (ns, ()))

  // Create a State that retrieves the current state
  def get[S]: State[S, S] = State(s =&amp;gt; (s, s))

  // Create a State that modifies the current state using a function
  def modify[S](fx: S =&amp;gt; S): State[S, Unit] = State(s =&amp;gt; (fx(s), ()))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;put Method: This method creates a State that replaces the current state with a new state ns. The result type is Unit because it doesn't return any meaningful value.&lt;/p&gt;

&lt;p&gt;get Method: This method creates a State that retrieves the current state. It returns the current state as both the new state and the result.&lt;/p&gt;

&lt;p&gt;modify Method: This method creates a State that modifies the current state using a provided function fx. It applies fx to the current state and returns the modified state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Functor Type Class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait Functor[F[_]] {
  def fmap[A, B](fa: F[A])(f: A =&amp;gt; B): F[B]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Functor Trait: This trait defines a type class for functors, which are types that can be mapped over. It has a method fmap that takes a functor fa containing a value of type A and a function f that transforms A into B. It returns a functor containing a value of type B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Functor Instance for State&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object Functor {
  // Functor instance for State using a type lambda
  given [S]: Functor[[A] =&amp;gt;&amp;gt; State[S, A]] with {
    override def fmap[A, B](a: State[S, A])(fx: A =&amp;gt; B): State[S, B] = State { s =&amp;gt;
      val (newState, value) = a.run(s)
      (newState, fx(value))
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Functor Instance: This provides an instance of the Functor type class for the State monad. The given keyword is used to define an implicit instance.&lt;br&gt;
fmap Implementation: The fmap method is implemented to apply the function fx to the result of the state computation while preserving the state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Monad Type Class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abstract class Monad[M[_]](using functor: Functor[M]) {
  def pure[A](a: A): M[A]
  def flatMap[A, B](a: M[A])(fx: A =&amp;gt; M[B]): M[B]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monad Trait: This abstract class defines a type class for monads, which are types that support chaining operations. It requires an implicit Functor instance.&lt;/p&gt;

&lt;p&gt;pure Method: This method lifts a value of type A into the monad M.&lt;/p&gt;

&lt;p&gt;flatMap Method: This method allows for chaining operations by taking a monadic value a and a function fx that returns a new monadic value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Monad Instance for State&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`object StateInstance {
  given [S]: Monad[[A] =&amp;gt;&amp;gt; State[S, A]] with {
    override def pure[A](a: A): State[S, A] = State(s =&amp;gt; (s, a))

    override def flatMap[A, B](a: State[S, A])(fx: A =&amp;gt; State[S, B]): State[S, B] = State { s =&amp;gt;
      val (newState, value) = a.run(s)
      fx(value).run(newState)
    }
  }
}`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monad Instance: This provides an instance of the Monad type class for the State monad.&lt;/p&gt;

&lt;p&gt;pure Implementation: The pure method creates a State that returns the value a while keeping the state unchanged.&lt;/p&gt;

&lt;p&gt;flatMap Implementation: The flatMap method allows chaining stateful computations. It runs the initial state computation, retrieves the new state and value, and then applies the function fx to the value, running the resulting state computation with the new state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Extension Methods for State&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension [S, A](state: State[S, A]) {
  // Map a function over the result of a State
  infix def map[B](f: A =&amp;gt; B)(using functor: Functor[[A] =&amp;gt;&amp;gt; State[S, A]]): State[S, B] = 
    functor.fmap(state)(f)

  infix def flatMap[B](f: A =&amp;gt; State[S, B])(using monad: Monad[[A] =&amp;gt;&amp;gt; State[S, A]]): State[S, B] = 
    monad.flatMap(state)(f)  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extension Methods: These methods add map and flatMap to the State class, allowing for more convenient usage of the State monad.&lt;br&gt;
map Method: This method allows you to apply a function f to the result of a State computation.&lt;br&gt;
flatMap Method: This method allows you to chain stateful computations using a function that returns a new State.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Extension Method to Lift a Value into State&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;extension &lt;a href="https://dev.toa:%20A"&gt;A&lt;/a&gt; {&lt;br&gt;
  def pureState[S]: State[S, A] = State(s =&amp;gt; (s, a))&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;pureState Method: This extension method allows you to lift a value a into a State monad, creating a stateful computation that returns a while keeping the state unchanged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Example Usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object StateExample {
  import com.example.Functor.given
  // import com.example.StateInstance.given

  type StringState[A] = State[String, A]

  def main(args: Array[String]): Unit = {
    given Monad[StringState] = StateInstance.given_Monad_State[String]

    val s = for {
      x &amp;lt;- 10.pureState[String] 
      os &amp;lt;- State.get[String]
      y &amp;lt;- 20.pureState[String]  
      _ &amp;lt;- State.put(os + " boom")
      z &amp;lt;- 30.pureState[String] 
      _ &amp;lt;- State.get[String].flatMap { ns =&amp;gt; State.put(ns + " baam") }
    } yield { x + y + z }

    val (s3, r3) = s.run("hello")
    println(s"Example 3 - State: $s3, Result: $r3")
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;StateExample Breakdown&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s the relevant part of the StateExample code again for reference:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: x &amp;lt;- 10.pureState[String]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This line lifts the value 10 into the State monad. The state remains unchanged at this point.&lt;br&gt;
The result of this operation is that x will hold the value 10.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: os &amp;lt;- State.get[String]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The get operation retrieves the current state.&lt;br&gt;
At this point, the initial state is "hello" (the argument passed to s.run("hello")).&lt;br&gt;
The result of this operation is that os will hold the value "hello".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: y &amp;lt;- 20.pureState[String]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similar to Step 1, this line lifts the value 20 into the State monad.&lt;br&gt;
The state is still unchanged at this point.&lt;br&gt;
The result of this operation is that y will hold the value 20.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: _ &amp;lt;- State.put(os + " boom")&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The put operation replaces the current state with a new state. Here, it takes the value of os (which is "hello") and appends " boom" to it.&lt;br&gt;
The new state becomes "hello boom".&lt;br&gt;
This operation does not return a value (hence the underscore _), but it modifies the state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: z &amp;lt;- 30.pureState[String]&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This line lifts the value 30 into the State monad.&lt;br&gt;
The state is still "hello boom" at this point.&lt;br&gt;
The result of this operation is that z will hold the value 30.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: _ &amp;lt;- State.get[String].flatMap { ns =&amp;gt; State.put(ns + " baam") }&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, State.get[String] retrieves the current state, which is now "hello boom".&lt;br&gt;
The result of this get operation is that ns will hold the value "hello boom".&lt;br&gt;
The flatMap method is then used to chain another operation. It takes the value of ns and appends " baam" to it, creating a new state of "hello boom baam".&lt;br&gt;
The put operation replaces the current state with this new state.&lt;br&gt;
Again, this operation does not return a value (hence the underscore _).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Result Calculation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After all these steps, the final result of the for comprehension is calculated:&lt;/p&gt;

&lt;p&gt;Final Result Calculation&lt;br&gt;
After all these steps, the final result of the for comprehension is calculated:&lt;/p&gt;

&lt;p&gt;yield { x + y + z }&lt;/p&gt;

&lt;p&gt;Here, x is 10, y is 20, and z is 30.&lt;br&gt;
The final result is .&lt;br&gt;
Summary of State Changes&lt;br&gt;
Initial State: "hello"&lt;br&gt;
After Step 2 (get): State remains "hello", os is "hello".&lt;br&gt;
After Step 4 (put): State changes to "hello boom".&lt;br&gt;
After Step 6 (get and put): State changes to "hello boom baam".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Output&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the state computation is run with the initial state "hello":&lt;br&gt;
val (s3, r3) = s.run("hello")&lt;/p&gt;

&lt;p&gt;s3 will hold the final state, which is "hello boom baam".&lt;br&gt;
r3 will hold the result of the computation, which is 60.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The output will be:&lt;/strong&gt;&lt;br&gt;
Example 3 - State: hello boom baam, Result: 60&lt;/p&gt;

&lt;p&gt;the full gist can be found at &lt;br&gt;
[&lt;a href="https://gist.github.com/depareddy/a0bfb88b9cdfa627395cefcbe0563a5e" rel="noopener noreferrer"&gt;https://gist.github.com/depareddy/a0bfb88b9cdfa627395cefcbe0563a5e&lt;/a&gt;]&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Exploring JSON Encoding in Scala: The Role of Macros and Derived Encoders</title>
      <dc:creator>Depa Reddy</dc:creator>
      <pubDate>Sat, 15 Mar 2025 10:12:19 +0000</pubDate>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed/exploring-json-encoding-in-scala-the-role-of-macros-and-derived-encoders-4a05</link>
      <guid>https://dev.to/depa_reddy_5e0e3025aa6eed/exploring-json-encoding-in-scala-the-role-of-macros-and-derived-encoders-4a05</guid>
      <description>&lt;p&gt;the entire source code user here can be found at below gist.&lt;br&gt;
&lt;a href="https://gist.github.com/depareddy/ce6f1500af400f69752beb5a9da05bbf" rel="noopener noreferrer"&gt;https://gist.github.com/depareddy/ce6f1500af400f69752beb5a9da05bbf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An encoder is like a helper that takes case class  turns it into this special code (JSON format).case class in scala can defined like below.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;case class Person(name: String, age: Int)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In our code, we have a special helper called JsonEncoder:&lt;br&gt;
JsonEncoder Trait: The JsonEncoder trait defines a type class for encoding values into JSON strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait JsonEncoder[T] {
  def encode(value: T): String
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This trait allows for polymorphic behavior, enabling different types to be encoded in a consistent manner.&lt;/p&gt;

&lt;p&gt;Primitive Type Encoders: Implicit encoders for primitive types are defined using given:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
given stringEncoder: JsonEncoder[String] with
      def encode(value: String): String = s""""$value""""

    given intEncoder: JsonEncoder[Int] with
      def encode(value: Int): String = value.toString

    given booleanEncoder: JsonEncoder[Boolean] with
      def encode(value: Boolean): String = value.toString

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List Encoder: A generic encoder for lists is provided, which recursively uses the element encoder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;given listEncoder[T](using encoder: JsonEncoder[T]): JsonEncoder[List[T]] with
      def encode(list: List[T]): String = 
        list.map(encoder.encode).mkString("[", ", ", "]") 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inline for Compile-Time Resolution&lt;/p&gt;

&lt;p&gt;What it does: Forces the compiler to evaluate expressions or patterns at compile time instead of runtime.&lt;br&gt;
inline: This keyword indicates that the method can be inlined by the compiler, which can lead to performance optimizations. It allows the compiler to replace calls to this method with the method's body at compile time.&lt;/p&gt;

&lt;p&gt;Let's break down the below given instance in detail, focusing on how it works to automatically generate JSON encoders for case classes in Scala 3. This part of the code is crucial for the functionality of the JSON encoding mechanism.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inline given derived[T](using m: Mirror.Of[T]): JsonEncoder[T] = new JsonEncoder[T] {
  def encode(value: T): String = {
    inline m match {
      case p: Mirror.ProductOf[T] =&amp;gt; 
        val labels = summonLabels[p.MirroredElemLabels]
        println(s"labels:$labels")
        val encoders = summonEncoders[p.MirroredElemTypes]
        val values = value.asInstanceOf[Product].productIterator.toList
        val encodedFields = (labels, encoders, values).zipped.map {
          (label, encoder, value) =&amp;gt;
            s""""$label": ${encoder.asInstanceOf[JsonEncoder[Any]].encode(value)}"""
        }
        s"{${encodedFields.mkString(", ")}}"
      case _ =&amp;gt; throw new IllegalArgumentException(s"Unsupported type: ${m.toString}")
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The derived method automates the creation of type class instances (e.g., JsonEncoder[Person]) for case classes/sealed traits by leveraging compile-time metaprogramming.  &lt;/p&gt;

&lt;p&gt;The Compiler Calls derived&lt;br&gt;
When you write&lt;br&gt;
&lt;code&gt;val perJson = encode(per) // Requires JsonEncoder[Person]&lt;/code&gt;&lt;br&gt;
The compiler:&lt;br&gt;
Looks for a given JsonEncoder[Person] in scope.&lt;br&gt;
If none exists, it tries to derive one using the above derived method  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1)Inline Given Instance:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inline given derived[T] (using m: Mirror.Of[T]): JsonEncoder[T]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Inline Given Instance:&lt;br&gt;
This defines an implicit instance of JsonEncoder[T] for any type T that has a corresponding Mirror.&lt;br&gt;
using m: Mirror.Of[T]: This means that the method requires an implicit Mirror for type T. The Mirror provides reflection capabilities to inspect the structure of the case class.&lt;br&gt;
The Mirror.Of[T] type provides compile-time metadata about T (e.g., field names/types for case classes).&lt;br&gt;
Mirror.Of[T] is a type class automatically generated by the Scala 3 compiler for case classes/sealed traits.&lt;/p&gt;

&lt;p&gt;Is it a case class (product) or sealed trait (sum)?&lt;br&gt;
it tells What are the field names and types (for case classes)?&lt;br&gt;
similarly What are the subtypes (for sealed traits)?&lt;/p&gt;

&lt;p&gt;The compiler generates:&lt;/p&gt;

&lt;p&gt;Mirror.ProductOf[Person] {&lt;br&gt;
  type MirroredElemLabels = ("name", "age")&lt;br&gt;
  type MirroredElemTypes = (String, Int)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;inline match on m ensures the compiler checks if T is a case class (product type) or a sum type (e.g., sealed trait) during compilation.&lt;br&gt;
Without inline, this check would happen at runtime, leading to errors or inefficiency.&lt;/p&gt;

&lt;p&gt;inline for Recursive Type-Level Computations&lt;br&gt;
What it does: Unrolls recursion over type-level tuples (e.g., field labels/types) at compile time.&lt;br&gt;
**&lt;br&gt;
2) Summoning Labels:**&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val labels = summonLabels[p.MirroredElemLabels]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;p.MirroredElemLabels is a type-level representation of the names of the fields in the case class T. The summonLabels method retrieves these names as a list of strings.&lt;br&gt;
This allows us to know what keys to use in the JSON output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // Helper to summon field labels
    private inline def summonLabels[T &amp;lt;: Tuple]: List[String] = inline erasedValue[T] match {
      case _: EmptyTuple =&amp;gt; Nil
      case _: (head *: tail) =&amp;gt; constValue[head].toString :: summonLabels[tail]
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;summonLabels iterates over the type-level tuple of field labels (e.g., ("name", "age") for Person case class).&lt;br&gt;
inline ensures the compiler recursively resolves each label to a String and builds a List[String] during compilation.&lt;br&gt;
Without inline, the recursion would fail because type-level tuples exist only at compile time.&lt;/p&gt;

&lt;p&gt;erasedValue and Type Safety&lt;/p&gt;

&lt;p&gt;erasedValue[T] Creates a "fake" value of type T that exists only at compile time.This is necessary because in Scala, pattern matching typically works on values, not types. By using erasedValue, the compiler can inspect the structure of T.&lt;/p&gt;

&lt;p&gt;The compiler pretends to create a runtime value of type T (e.g., ("name", "age")), even though T is a type.&lt;br&gt;
This "fake" value is used to pattern-match on the structure of T.&lt;/p&gt;

&lt;p&gt;The compiler inspects the structure of T (e.g., is it a tuple?).&lt;br&gt;
For a &lt;code&gt;tuple T = ("name", "age"):&lt;/code&gt;&lt;br&gt;
Match &lt;code&gt;head *: tail, where head = "name", tail = ("age").&lt;/code&gt;&lt;br&gt;
Extract head as a value using constValue&lt;a href="https://dev.toreturns"&gt;head&lt;/a&gt;.&lt;br&gt;
Recurse on tail to process "age".&lt;/p&gt;

&lt;p&gt;For Person, the compiler:&lt;br&gt;
Materializes T = ("name", "age") via erasedValue[T].&lt;br&gt;
Matches head *: tail to decompose the tuple.&lt;br&gt;
Extracts "name" and "age" using constValue.&lt;br&gt;
Returns List("name", "age").&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Summoning Encoders:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val encoders = summonEncoders[p.MirroredElemTypes]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Similar to labels, p.MirroredElemTypes provides the types of the fields in the case class. The summonEncoders method retrieves the corresponding JsonEncoder instances for each field type.&lt;br&gt;
This is crucial for encoding each field correctly based on its type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; // Helper to summon encoders for each field type
    private inline def summonEncoders[T &amp;lt;: Tuple]: List[JsonEncoder[_]] = 
      inline erasedValue[T] match {
        case _: EmptyTuple =&amp;gt; Nil
        case _: (t *: ts) =&amp;gt; summonInline[JsonEncoder[t]] :: summonEncoders[ts]
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;/p&gt;

&lt;p&gt;val encoder: JsonEncoder[String] =summonInline[JsonEncoder[String]]&lt;br&gt;
Retrieves the JsonEncoder[String] instance at compile time.&lt;br&gt;
If no instance exists, compilation fails.&lt;/p&gt;

&lt;p&gt;Recursively summons encoders for each type in a tuple T.&lt;br&gt;
Example: For T = (String, Int), it returns List(JsonEncoder[String], JsonEncoder[Int]).&lt;/p&gt;

&lt;p&gt;SummonEncoders uses summonInline to fetch encoders for String and Int.If an encoder for String or Int is missing, compilation fails immediately.&lt;/p&gt;

&lt;p&gt;Why Use summonInline Over summon?&lt;br&gt;
Guaranteed Compile-Time Resolution:&lt;br&gt;
summon might resolve instances at runtime in generic contexts, but summonInline forces resolution during compilation.&lt;br&gt;
Integration with inline:Required for code generation in inline methods (e.g., deriving JSON encoders for case classes).&lt;/p&gt;

&lt;p&gt;Example: Deriving a JSON Encoder&lt;br&gt;
&lt;code&gt;&lt;br&gt;
// Derive encoder for Person&lt;br&gt;
given JsonEncoder[Person] with {&lt;br&gt;
  def encode(p: Person): String = {&lt;br&gt;
    val labels = summonLabels[Person.derived.MirroredElemLabels] // ("name", "age")&lt;br&gt;
    val encoders = summonEncoders[Person.derived.MirroredElemTypes] // (JsonEncoder[String], JsonEncoder[Int])&lt;br&gt;
    // Use labels/encoders to generate JSON&lt;br&gt;
  }&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4) Extracting Values:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val values = value.asInstanceOf[Product].productIterator.toList&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The value is cast to Product, which is the base trait for all case classes. The productIterator method returns an iterator over the fields of the case class.&lt;/p&gt;

&lt;p&gt;The toList method converts this iterator into a list of values, which corresponds to the fields of the case class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5) Encoding Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val encodedFields = (labels, encoders, values).zipped.map {&lt;br&gt;
  (label, encoder, value) =&amp;gt;&lt;br&gt;
    s""""$label": ${encoder.asInstanceOf[JsonEncoder[Any]].encode(value)}"""&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The zipped method combines the three lists: labels, encoders, and values into tuples. Each tuple contains a label, an encoder, and a value.&lt;br&gt;
The map function iterates over these tuples, using the encoder to encode each value and formatting it as a JSON key-value pair.&lt;br&gt;
The result is a list of strings representing the encoded fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5) Constructing the JSON Object:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;s"{${encodedFields.mkString(", ")}}"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, the encoded fields are joined together with commas and wrapped in curly braces to form a valid JSON object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6) Full Derivation Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Request an Encoder:&lt;/p&gt;

&lt;p&gt;encode(Person("Alice", 25)) // Requires JsonEncoder[Person]&lt;/p&gt;

&lt;p&gt;1) Compiler Searches for JsonEncoder[Person]:&lt;br&gt;
2) Checks implicit/given instances in scope.&lt;br&gt;
3) Falls back to JsonEncoder.derived if none found.&lt;br&gt;
4) Compiler Derives the Encoder:&lt;br&gt;
5) Generates a Mirror.Of[Person].&lt;br&gt;
6) Calls derived[Person] with the Mirror instance.&lt;br&gt;
7) Uses inline to detect Person is a product type (case class).&lt;br&gt;
8) Recursively resolves field labels ("name", "age") and types (String, Int).&lt;br&gt;
9) Summons JsonEncoder[String] and JsonEncoder[Int] at compile time.&lt;br&gt;
10) Generates code to serialize Person as {"name": "value", "age": 21}.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing a Generic Foldable Type Class in Scala with List and Tuple Instances</title>
      <dc:creator>Depa Reddy</dc:creator>
      <pubDate>Sun, 09 Feb 2025 17:47:15 +0000</pubDate>
      <link>https://dev.to/depa_reddy_5e0e3025aa6eed/implementing-a-generic-foldable-type-class-in-scala-with-list-and-tuple-instances-31bo</link>
      <guid>https://dev.to/depa_reddy_5e0e3025aa6eed/implementing-a-generic-foldable-type-class-in-scala-with-list-and-tuple-instances-31bo</guid>
      <description>&lt;p&gt;In this short tutorial we will implement A Generic Foldable Type Class in Scala: From Lists to Custom Tuple Types.We will cover key concepts such as type lambdas, type classes, type class instances, and extension methods.full code can be found at this gist &lt;a href="https://gist.github.com/depareddy/8446b890b87ea02bfa5aed530b80e47e" rel="noopener noreferrer"&gt;FoldableInstances.scala&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Type lambdas in code&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Type lambdas in Scala are a way to define anonymous type-level functions. They allow you to create new types on the fly by applying transformations to existing types.&lt;br&gt;
This is particularly useful when working with higher-kinded types (types that take other types as parameters, like List, Option, or Either).&lt;/p&gt;

&lt;p&gt;The syntax for a type lambda in Scala is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type TypeLambda = [Param1, Param2, ...] =&amp;gt;&amp;gt; ResultType

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Type Alias: TupleMy2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TupleMy2 is defined as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type TupleMy2 = [X] =&amp;gt;&amp;gt; (X, X)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;p&gt;TupleMy2 is a type-level function that takes a single type parameter X.&lt;br&gt;
It produces a tuple type (X, X) where both elements of the tuple are of type X.&lt;br&gt;
For example:&lt;/p&gt;

&lt;p&gt;If X is Int, then TupleMy2[Int] is (Int, Int).&lt;/p&gt;

&lt;p&gt;If X is String, then TupleMy2[String] is (String, String).&lt;/p&gt;

&lt;p&gt;This allows us to generalize folding operations over both lists and tuples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defining the Foldable Type Class&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type classes are a powerful and flexible feature in Scala  that allow you to define generic behavior that can be applied to different types without modifying those types&lt;/p&gt;

&lt;p&gt;In below provided code, the Foldable trait is a type class that abstracts the concept of "foldability" for different data structures.&lt;/p&gt;

&lt;p&gt;Foldable is a type class parameterized by a higher-kinded type C[_]&lt;/p&gt;

&lt;p&gt;In this example, Foldable is a type class that defines a method foldr for that types must implement to be considered "foldable."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;trait Foldable[C[_]]:
  def foldr[A, B](xs: C[A])(init: B)(fx: (A, B) =&amp;gt; B): B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create Type Class Instances&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, we can create instances of the Foldable type class for different types:&lt;/p&gt;

&lt;p&gt;In scala The given keyword helps define type class instances that the compiler can inject automatically.&lt;/p&gt;

&lt;p&gt;Here we  creates type class instance for specific types (List and TupleMy2)&lt;/p&gt;

&lt;p&gt;Each instance provides a concrete implementation of foldr&lt;br&gt;
Instances are named (listFoldable, tuple2Foldable) but names are optional&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;given listFoldable: Foldable[List] with
  override def foldr[A, B](xs: List[A])(init: B)(fx: (A, B) =&amp;gt; B): B =
    xs.foldRight(init)(fx)

given tuple2Foldable: Foldable[TupleMy2] with
  override def foldr[A, B](xs: TupleMy2[A])(init: B)(fx: (A, B) =&amp;gt; B): B =
    fx(xs._1, fx(xs._2, init))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List Instance:Uses List's built-in foldRight to implement foldr.&lt;br&gt;
Example: &lt;code&gt;List(1, 2, 3).foldRight(0)(_ + _)&lt;/code&gt; sums the elements.&lt;/p&gt;

&lt;p&gt;Tuple Instance:For a tuple (a, b), applies fx to b and init first, then to a and the result.&lt;br&gt;
Example: &lt;code&gt;("a", "g").foldRight("init")(_ + _)&lt;/code&gt; produces "initga".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extension Methods: FoldableOps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The extension keyword is used to define an extension method. This allows you to add methods to existing types without modifying their source code.&lt;br&gt;
its purpose is to add a foldRight method to any type with a Foldable instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;object FoldableOps:
  extension [C[_], A](xs: C[A])(using foldable: Foldable[C])
    def foldRight[B](init: B)(fx: (A, B) =&amp;gt; B) =
      summon[Foldable[C]].foldr(xs)(init)(fx)`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Components of the Extension Method&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extension Method Definition:
The syntax &lt;code&gt;extension [C[_], A](xs: C[A])&lt;/code&gt; indicates that 
this extension method applies to any type constructor C that 
takes one type parameter (like List, Option, etc.) and to any 
type A.&lt;/li&gt;
&lt;li&gt;Using Clause:
The &lt;code&gt;(using foldable: Foldable[C])&lt;/code&gt; part indicates that this
method requires an implicit Foldable[C] instance to be 
available in the scope. This is crucial because the method 
relies on the foldr implementation provided by the Foldable 
type class.&lt;/li&gt;
&lt;li&gt;Method Implementation:
The method &lt;code&gt;foldRight[B](init: B)(fx: (A, B) =&amp;gt; B)&lt;/code&gt; takes two 
parameters:
&lt;strong&gt;init:&lt;/strong&gt; The initial value of type B for the fold operation.
&lt;strong&gt;fx:&lt;/strong&gt; A  function that takes an element of type A and an 
       accumulator of type B, returning a new accumulator of 
       type B.
Inside the method, &lt;code&gt;summon[Foldable[C]]&lt;/code&gt; is called to retrieve the implicit Foldable[C] instance. This instance is then used to call the foldr method, passing in the collection xs, the initial value init, and the folding function fx.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How It Works in Practice:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// For List
List("a", "b").foldRight("init")(_ + _)

// For Tuple
("a", "g").foldRight("init")(_ + _)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you call foldRight on a List or TupleMy2, Scala will automatically look for an appropriate Foldable instance based on the type of the collection:&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;List("a", "b")&lt;/code&gt;, the compiler finds the listFoldable instance because List is a type that has a Foldable instance defined.&lt;br&gt;
For stringTuple, which is of type TupleMy2[String], the compiler finds the tuple2Foldable instance.then it Injects the instance implicitly into the foldRight call.&lt;/p&gt;

&lt;p&gt;Brings all given instances from FoldableInstances into scope,like this.Required for the compiler to find the instances during implicit resolution&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.example.FoldableInstances.given
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Extension Method Execution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;summon[Foldable[List]].foldr(List("a", "b", "c", "d"))("init")((x, acc) =&amp;gt; acc + x)`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The foldRight method is executed, and the compiler translates the call to &lt;code&gt;summon[Foldable[C]]&lt;/code&gt; retrieves the instance from implicit scope.The foldr method of the listFoldable instance is called, performing the fold operation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test Code&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Folding a List
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val list = List("a", "b", "c", "d").foldRight("init")((x, a) =&amp;gt; a + x)
println("list" + list) // Output: "listinitdcba"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Behavior:&lt;/strong&gt; Folds the list from right to left, appending elements to init.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with "init".&lt;/li&gt;
&lt;li&gt;Process "d" → "initd".&lt;/li&gt;
&lt;li&gt;Process "c" → "initdc".&lt;/li&gt;
&lt;li&gt;Process "b" → "initdcb".&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Process "a" → "initdcba".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Folding a Tuple&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Behavior: Folds the tuple ("a", "g") from right to left.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start with "init".&lt;/li&gt;
&lt;li&gt;Process "g" → "initg".&lt;/li&gt;
&lt;li&gt;Process "a" → "initga".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Key Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define Type Class: Foldable trait with required operations&lt;/li&gt;
&lt;li&gt;Provide Instances: Implementations for specific types using given&lt;/li&gt;
&lt;li&gt;Import Instances: Make instances available in current scope&lt;/li&gt;
&lt;li&gt;Use via Extension: Call methods that require the type class instance&lt;/li&gt;
&lt;li&gt;Compiler Resolution: Automatically selects correct instance based on type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;. Key Concepts&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type Classes: Foldable abstracts folding logic for different containers.&lt;/li&gt;
&lt;li&gt;Higher-Kinded Types: C[_] generalizes over types like List and TupleMy2.&lt;/li&gt;
&lt;li&gt;Type Lambdas: TupleMy2 is defined as a type-level function for tuples.&lt;/li&gt;
&lt;li&gt;Extension Methods: Enable syntax like container.foldRight(...
)&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
