<?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: Sadanand Dodawadakar</title>
    <description>The latest articles on DEV Community by Sadanand Dodawadakar (@sadanand_dodawadakar_10b2).</description>
    <link>https://dev.to/sadanand_dodawadakar_10b2</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%2F2489800%2F30488417-dad1-4cdd-b58f-632f4abfc16b.png</url>
      <title>DEV Community: Sadanand Dodawadakar</title>
      <link>https://dev.to/sadanand_dodawadakar_10b2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sadanand_dodawadakar_10b2"/>
    <language>en</language>
    <item>
      <title>What make Rust blazing fast?</title>
      <dc:creator>Sadanand Dodawadakar</dc:creator>
      <pubDate>Sat, 18 Jan 2025 10:48:30 +0000</pubDate>
      <link>https://dev.to/sadanand_dodawadakar_10b2/what-make-rust-blazing-fast-5anj</link>
      <guid>https://dev.to/sadanand_dodawadakar_10b2/what-make-rust-blazing-fast-5anj</guid>
      <description>&lt;p&gt;Rust has earned immense popularity for being a blazing fast programming language, often competing or even outperforming established programming languages like C and C++. But what truly sets Rust apart? This story explores the technical features and design principles that make Rust a powerhouse for performance.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Zero-Cost Abstractions
&lt;/h3&gt;

&lt;p&gt;Rust adheres to the principle of zero-cost abstractions, meaning that high-level constructs in the language introduce no additional runtime overhead. Features like iterators, closures, and traits compile down to highly optimised machine code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let v = vec![1, 2, 3, 4];
let sum: i32 = v.iter().filter(|&amp;amp;&amp;amp;x| x % 2 == 0).sum();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rust compiler optimises the iterator and filter into a loop with no abstraction penalty.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Memory Safety Without Garbage Collection
&lt;/h3&gt;

&lt;p&gt;Unlike Java or Go, Rust achieves memory safety without relying on a garbage collector. This eliminates the performance overhead caused by periodic garbage collection pauses.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ownership and Borrowing
&lt;/h4&gt;

&lt;p&gt;Rust uses an ownership system with strict rules about how memory is accessed. The compiler ensures this at compile time.&lt;/p&gt;

&lt;p&gt;Memory is not accessed after it is freed (no use-after-free errors).&lt;/p&gt;

&lt;p&gt;Only one mutable reference or multiple immutable references exist simultaneously.&lt;/p&gt;

&lt;h4&gt;
  
  
  Deterministic Deallocation
&lt;/h4&gt;

&lt;p&gt;Memory is deallocated immediately when it goes out of scope, akin to RAII in C++, leading to predictable performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Fearless Concurrency
&lt;/h3&gt;

&lt;p&gt;Concurrency is notoriously difficult to get right due to data races. Rust enables “fearless concurrency” with its ownership model and type system.&lt;/p&gt;

&lt;p&gt;Elimination of Data Races at Compile-Time&lt;br&gt;
Data races are a common source of bugs and performance issues in concurrent systems. Rust leverages its ownership model and borrow checker to enforce concurrency rules at compile time&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exclusive Access:&lt;/strong&gt; Rust ensures that data is either mutably borrowed by one thread or immutably borrowed by multiple threads, but not both. Two threads cannot mutate the same piece of data simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Undefined Behaviour:&lt;/strong&gt; By catching concurrency issues during compilation, Rust eliminates runtime errors like segmentation faults, which can slow down or crash programs in other languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compile-time safety ensures that Rust’s concurrent programs are “error-free by design”, eliminating expensive runtime checks, which often degrade performance.&lt;/p&gt;
&lt;h4&gt;
  
  
  Efficient Use of System Resources
&lt;/h4&gt;

&lt;p&gt;Rust’s fearless concurrency directly translates to better system resource utilisation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fine-Grained Locking:&lt;/strong&gt; Rust’s Mutex and RwLock primitives allow precise control over shared data, reducing contention and enabling efficient multi-threaded execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-** Zero-Cost Abstractions:** Unlike languages with garbage collection or runtime checks for thread safety, Rust relies on compile-time guarantees. This ensures no runtime performance penalties.&lt;br&gt;
_&lt;/p&gt;
&lt;h4&gt;
  
  
  Low-Overhead Concurrency Primitives
&lt;/h4&gt;

&lt;p&gt;Rust’s standard library provides efficient concurrency tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;std::thread :&lt;/strong&gt; Lightweight abstractions for spawning OS threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;std::sync :&lt;/strong&gt;High-performance synchronisation primitives like High-_performance synchronisation primitives like Condvar, Mutex , and RwLock.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Asynchronous Concurrency: Maximising Throughput
&lt;/h4&gt;

&lt;p&gt;Rust’s asynchronous programming model, built around async/await, complements its multithreading capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Futures-Based Execution:&lt;/strong&gt; Rust’s async tasks are lightweight and avoid blocking threads, allowing applications to handle millions of operations efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-Driven Execution:&lt;/strong&gt; Frameworks like tokio and async-std use event loops to schedule tasks efficiently, reducing the need for expensive thread context switches._&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Deterministic Behaviour and Predictable Performance
&lt;/h4&gt;

&lt;p&gt;concurrency in Rust eliminates common pitfalls like race conditions and deadlocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Race Conditions:&lt;/strong&gt; Rust enforces data access rules that prevent inconsistent states caused by unsynchronised threads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deadlocks:&lt;/strong&gt; While Rust doesn’t eliminate deadlocks, its ownership model and explicit synchronisation primitives make potential deadlocks easier to identify and debug._&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By eliminating these issues, Rust ensures that concurrent programs run “predictably and efficiently”, even under high workloads.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Monomorphisation of Generics
&lt;/h3&gt;

&lt;p&gt;Rust uses monomorphisation for generics, generating specific code for each type used with a generic function or structure. This results in type-specific, highly optimised code at the cost of slightly larger binary sizes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fn add&amp;lt;T: std::ops::Add&amp;lt;Output = T&amp;gt;&amp;gt;(a: T, b: T) -&amp;gt; T {
    a + b
}

fn main() {
    let int_sum = add(1, 2);      // Optimized for integers
    let float_sum = add(1.0, 2.0); // Optimized for floats
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiler creates separate versions of add for integers and floats, eliminating runtime type checking and improving performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Minimal Runtime
&lt;/h3&gt;

&lt;p&gt;One of the standout features of Rust is its minimal runtime overhead. This design choice ensures that Rust programs are not only safe and concurrent but also incredibly fast. Let’s break this concept down in detail.&lt;/p&gt;

&lt;p&gt;Runtime overhead refers to the extra processing and resource consumption added by a language’s runtime environment to manage features like memory allocation, garbage collection, thread management, and more.&lt;/p&gt;

&lt;p&gt;Languages like Java introduce significant runtime overhead due to their reliance on garbage collection and virtual machines (e.g., JVM for Java). Rust, on the other hand, avoids these overheads, delivering near-zero-cost abstractions and runtime efficiency.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Static Linking
&lt;/h3&gt;

&lt;p&gt;Rust uses static linking by default, embedding all dependencies and required code directly into the executable. This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster runtime because there’s no need to dynamically resolve external libraries.&lt;/li&gt;
&lt;li&gt;Predictable performance, as the binary includes everything needed for execution._&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this increases the executable size, it eliminates runtime delays due to dynamic linking, making execution faster. However, “static linking may increase the load time.”&lt;/p&gt;

&lt;p&gt;We will do the comparison of rust compiled binary and C compiled binary to understand intricacies in details in the following sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. LLVM Optimisations
&lt;/h3&gt;

&lt;p&gt;Rust leverages the LLVM backend, which performs aggressive optimisations to generate highly efficient executables. Key LLVM optimisations include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inlining:&lt;/strong&gt; Embeds function calls directly into the caller’s code to avoid the overhead of function calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loop Unrolling:&lt;/strong&gt; Optimises loops by reducing branching operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead Code Elimination:&lt;/strong&gt; Strips unused code from the final executable, ensuring only essential instructions remain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8. Low-Level Control with High-Level Guarantees
&lt;/h3&gt;

&lt;p&gt;Rust allows direct control over hardware and memory, similar to C/C++, while maintaining safety through its ownership model. In cases where performance-critical operations are needed, unsafe blocks provide the freedom to bypass some safety checks for raw hardware access.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rust ensures safe memory access by default, reducing debugging overhead.&lt;/li&gt;
&lt;li&gt;Unsafe code regions, when necessary, compile to raw, low-level instructions without safety checks, maximising speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  9. Efficient Memory Layout
&lt;/h3&gt;

&lt;p&gt;Rust compilers carefully optimise data structures for cache alignment and memory layout. Using attributes like #[repr(C)], Rust ensures predictable layouts that match system architecture, reducing cache misses and improving access times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#[repr(C)]
struct Point {
    x: f64,
    y: f64,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures Point is laid out in memory as contiguous x and y values, enabling efficient hardware-level access.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. LTO (Link-Time Optimisation)
&lt;/h3&gt;

&lt;p&gt;Rust supports Link-Time Optimization (LTO), which optimizes the binary by analysing and optimising across crate boundaries. LTO ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removal of redundant code and function calls.&lt;/li&gt;
&lt;li&gt;Cross-module inlining, improving execution speed._
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[profile.release]
lto = "thin"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  11. Whole-Program Compilation
&lt;/h3&gt;

&lt;p&gt;Rust compiles the entire program, including dependencies, into a single executable. This enables the compiler to:&lt;/p&gt;

&lt;p&gt;Inline functions across library boundaries.&lt;br&gt;
Optimise the entire program holistically, unlike languages that compile individual files separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  12. Optimised Panic Handling
&lt;/h3&gt;

&lt;p&gt;Rust includes panic handling for safety, but it optimises for the common case where no panics occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Panic code paths are generated separately, leaving the main execution path lightweight.&lt;/li&gt;
&lt;li&gt;Release builds can further strip panic messages for minimal overhead._&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Rust’s speed is a product of deliberate design, combining low-level control, memory safety, and zero-cost abstractions to deliver exceptional performance. It excels in scenarios requiring both high efficiency and reliability, making it a compelling choice for modern systems.&lt;/p&gt;

&lt;p&gt;Ultimately, Rust strikes a remarkable balance, offering developers the tools to build fast and safe software while acknowledging the complexity that comes with such power.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>performance</category>
      <category>cloudnative</category>
    </item>
    <item>
      <title>Generics in Go: Transforming Code Reusability</title>
      <dc:creator>Sadanand Dodawadakar</dc:creator>
      <pubDate>Tue, 07 Jan 2025 16:25:47 +0000</pubDate>
      <link>https://dev.to/sadanand_dodawadakar_10b2/generics-in-go-transforming-code-reusability-4nm6</link>
      <guid>https://dev.to/sadanand_dodawadakar_10b2/generics-in-go-transforming-code-reusability-4nm6</guid>
      <description>&lt;p&gt;Generics, introduced in Go 1.18, have revolutionised the way of writing reusable and type-safe code. Generics bring flexibility and power while maintaining Go’s philosophy of simplicity. However, understanding nuances, benefits, and how generics compare to traditional approaches (like interface{} ) requires a closer look.&lt;/p&gt;

&lt;p&gt;Let’s explore the intricacies of generics, delve into constraints, compare generics to interface{}, and demonstrate their practical applications. We’ll also touch upon performance considerations and binary size implications. Let’s dive in!&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Generics?
&lt;/h1&gt;

&lt;p&gt;Generics allow developers to write functions and data structures that can operate on any type while maintaining type safety. Instead of relying on interface{}, which involves type assertions in runtime, generics let you specify a set of constraints that dictate the permissible operations on the types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Syntax&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;func FunctionName[T TypeConstraint](parameterName T) ReturnType {
    // Function body using T
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;T:&lt;/em&gt;&lt;/strong&gt; A type parameter, representing a placeholder for the type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;TypeConstraint&lt;/em&gt;&lt;/strong&gt;: Restricts the type of &lt;strong&gt;&lt;em&gt;T&lt;/em&gt;&lt;/strong&gt; to a specific type or a set of types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;parameterName T&lt;/em&gt;&lt;/strong&gt;: The parameter uses the generic type &lt;strong&gt;&lt;em&gt;T&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;ReturnType&lt;/em&gt;&lt;/strong&gt;: The function can also return a value of type &lt;strong&gt;&lt;em&gt;T&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&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;func Sum[T int | float64](a, b T) T {
    return a + b
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;func Sum:&lt;/em&gt;&lt;/strong&gt; Declares the name of the function, Sum&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;[T int | float64]:&lt;/em&gt;&lt;/strong&gt; Specifies a type parameter list that introduces T as a type parameter, constrained to specific types (&lt;strong&gt;&lt;em&gt;int or float64&lt;/em&gt;&lt;/strong&gt;). Sum function can take only parameters either int or float64, not in combination, both have to either &lt;strong&gt;&lt;em&gt;int&lt;/em&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;em&gt;float64&lt;/em&gt;&lt;/strong&gt;. We will explore this further in below sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;(a, b T):&lt;/em&gt;&lt;/strong&gt; Declares two parameters, a and b, both of type &lt;strong&gt;&lt;em&gt;T&lt;/em&gt;&lt;/strong&gt; (the generic type).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;T:&lt;/em&gt;&lt;/strong&gt; Specifies the return type of the function, which matches the type parameter &lt;strong&gt;&lt;em&gt;T&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Constraints: Building blocks of Generics
&lt;/h2&gt;

&lt;p&gt;Constraints define what operations are valid for a generic type. Go provides powerful tools for constraints, including the experimental constraints package(&lt;strong&gt;&lt;em&gt;golang.org/x/exp/constraints&lt;/em&gt;&lt;/strong&gt;).&lt;/p&gt;
&lt;h3&gt;
  
  
  Built-in Constraints
&lt;/h3&gt;

&lt;p&gt;Go introduced built-in constraints with generics to provide type safety while allowing flexibility in defining reusable and generic code. These constraints enable developers to enforce rules on the types used in generic functions or types.&lt;/p&gt;
&lt;h3&gt;
  
  
  Go has below built-in constraints
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;any&lt;/strong&gt;: Represents any type. It’s an alias for interface{}. This is used when no constraints are needed
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func PrintValues[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;comparable&lt;/strong&gt;: Allows types that support equality comparison(== and !=). Useful for maps keys, duplicate detection or equality checks. This can not be used for maps, slices and functions, since these types don’t support direct comparison.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func CheckDuplicates[T comparable](items []T) []T {
    seen := make(map[T]bool)
    duplicates := []T{}
    for _, item := range items {
        if seen[item] {
            duplicates = append(duplicates, item)
        } else {
            seen[item] = true
        }
    }
    return duplicates
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Experimental constraints&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;constraints.Complex: Permits complex numeric types(complex64 and complex128).&lt;/li&gt;
&lt;li&gt;constraints.Float: Permits float numeric types(float32 and float64)&lt;/li&gt;
&lt;li&gt;constraints.Integer: Permits any integer both signed and unsigned (int8, int16, int32, int64, int, uint8, uint16, uint32, uint64 and uint)&lt;/li&gt;
&lt;li&gt;constraints.Signed: Permits any signed integer(int8, int16, int32, int64 and int)&lt;/li&gt;
&lt;li&gt;constraints.Unsigned: Permits any unsigned integer (uint8, uint16, uint32, uint64 and uint).&lt;/li&gt;
&lt;li&gt;constraint.Ordered: Permits types that allow comparison (&amp;lt;. &amp;lt;=, &amp;gt;, &amp;gt;=), all numeric types and string are supported(int, float64, string, etc).
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import (
     "golang.org/x/exp/constraints"
     "fmt"
)

func SortSlice[T constraints.Ordered](items []T) []T {
    sorted := append([]T{}, items...) // Copy slice
    sort.Slice(sorted, func(i, j int) bool {
        return sorted[i] &amp;lt; sorted[j]
    })
    return sorted
}

func main() {
    nums := []int{5, 2, 9, 1}
    fmt.Println(SortSlice(nums)) // Output: [1 2 5 9]

    words := []string{"banana", "apple", "cherry"}
    fmt.Println(SortSlice(words)) // Output: [apple banana cherry]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Custom Constraints
&lt;/h2&gt;

&lt;p&gt;Custom constraints are interfaces that define a set of types or type behaviours that a generic type parameter must satisfy. By creating your own constraints, we can;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Restrict types to a specific subset, such as numeric types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Require types to implement specific methods or behaviors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add more control and specificity to your generic functions and types.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Syntax&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;type Numeric interface {
    int | float64 | uint
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Example&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;type Number interface {
    int | int64 | float64
}

func Sum[T Number](a, b T) T {
    return a + b
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;Sum function&lt;/em&gt;&lt;/strong&gt; can be called using only int, int64 and float64 parameters.&lt;/p&gt;
&lt;h3&gt;
  
  
  Constraints by method
&lt;/h3&gt;

&lt;p&gt;If you want to enforce a type must implement certain methods, you can define it using those methods.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Formatter interface {
    Format() string
}

func PrintFormatted[T Formatter](value T) {
    fmt.Println(value.Format())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Formatter&lt;/em&gt;&lt;/strong&gt; constraint requires that any type used as &lt;strong&gt;&lt;em&gt;T&lt;/em&gt;&lt;/strong&gt; must have a Format method that returns a &lt;strong&gt;&lt;em&gt;string&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Combining Constraints
&lt;/h3&gt;

&lt;p&gt;Custom constraints can combine type sets and method requirements&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type AdvancedNumeric interface {
    int | float64
    Abs() float64
}

func Process[T AdvancedNumeric](val T) float64 {
    return val.Abs()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This constraint includes both specific types (&lt;strong&gt;&lt;em&gt;int, float54&lt;/em&gt;&lt;/strong&gt;) and requires the presence of an &lt;strong&gt;&lt;em&gt;abs&lt;/em&gt;&lt;/strong&gt; method.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generics vs interface{}
&lt;/h2&gt;

&lt;p&gt;Before introduction of generics, interface{} was used to achieve flexibility. However, this approach has limitations.&lt;/p&gt;
&lt;h3&gt;
  
  
  Type Safety
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;interface{}: Relies on runtime type assertions, increasing the chance of errors at runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generics: Offers compile-time type safety, catching errors early during development.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;interface{}: Slower due to additional runtime type checks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generics: Faster, as the compiler generates optimised code paths specific to types.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Code Readability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;interface{}: Often verbose and less intuitive, making the code harder to maintain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generics: Cleaner syntax leads to more intuitive and maintainable code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Binary Size
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;interface{}: Results in smaller binaries as it doesn’t duplicate code for different types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generics: Slightly increases binary size due to type specialisation for better performance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example&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;func Add(a, b interface{}) interface{} {
    return a.(int) + b.(int)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Code works well, type assertion is overhead. Add function can called with any argument, both a and b parameters can be of different types, however code will crash in the runtime.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func AddGeneric[T int | float64](a, b T) T {
    return a + b
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Generics eliminate the risk of runtime panics caused by incorrect type assertions and improve clarity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Generics produce specialised code for each type, leading to better runtime performance compared to interface{}.&lt;/p&gt;
&lt;h3&gt;
  
  
  Binary Size
&lt;/h3&gt;

&lt;p&gt;A trade-off exists: generics increase binary size due to code duplication for each type, but this is often negligible compared to the benefits.&lt;/p&gt;
&lt;h3&gt;
  
  
  Limitations of Go Generics
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Complexity in Constraints:&lt;/em&gt;&lt;/strong&gt; While constraints like constraints.Ordered simplify common use cases, defining highly customized constraints can become verbose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;No Type Inference in Structs:&lt;/em&gt;&lt;/strong&gt; Unlike functions, you must specify the type parameter explicitly for structs.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s := Stack[int]{} // Type parameter is required
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;&lt;em&gt;Limited to Compile-Time Constraints:&lt;/em&gt;&lt;/strong&gt; Go generics focus on compile-time safety, whereas languages like Rust offer more powerful constraints using lifetimes and traits.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let’s Benchmark — Better done than said
&lt;/h2&gt;

&lt;p&gt;We will implement a simple Queue with both interface{} and generic and benchmark the results.&lt;/p&gt;
&lt;h3&gt;
  
  
  Interface{} Queue implementation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
 "testing"
)

type QueueI struct {
 items []interface{}
}

func (q *QueueI) Enqueue(item interface{}) {
 q.items = append(q.items, item)
}

func (q *QueueI) Dequeue() interface{} {
 item := q.items[0]
 q.items = q.items[1:]
 return item
}

func BenchmarkInterfaceQueue(b *testing.B) {
 queue := QueueI{}
 for i := 0; i &amp;lt; b.N; i++ {
  queue.Enqueue(i)
  queue.Dequeue()
 }
}

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  Generic Queue Implementation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
 "testing"
)

type QueueG[T any] struct {
 items []T
}

func (q *QueueG[T]) Enqueue(item T) {
 q.items = append(q.items, item)
}

func (q *QueueG[T]) Dequeue() T {
 item := q.items[0]
 q.items = q.items[1:]
 return item
}

func BenchmarkGenericQueue(b *testing.B) {
 queue := QueueG[int]{}
 for i := 0; i &amp;lt; b.N; i++ {
  queue.Enqueue(i)
  queue.Dequeue()
 }
}

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

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go test -bench=. -benchmem
goos: darwin
goarch: amd64
pkg: becnh
cpu: VirtualApple @ 2.50GHz
BenchmarkGenericQueue-10        74805141                16.05 ns/op            8 B/op          1 allocs/op
BenchmarkInterfaceQueue-10      25719405                44.65 ns/op           24 B/op          1 allocs/op
PASS
ok      becnh   4.522s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Analysis of Results
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Execution Time:&lt;br&gt;
The generic implementation is approximately 63.64% faster than the interface{} version because it avoids runtime type assertions and operates directly on the given type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Allocations:&lt;br&gt;
The interface{} version makes 3x more allocations, primarily due to boxing/unboxing when inserting and retrieving values. This adds overhead to garbage collection.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For larger workloads, such as 1 million enqueue/dequeue operations, the performance gap widens. Real-world applications with high-throughput requirements (e.g., message queues, job schedulers) benefit significantly from generics.&lt;/p&gt;
&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Generics in Go strike a balance between power and simplicity, offers a practical solution for writing reusable and type-safe code. While not as feature-rich as Rust or C++, align perfectly with Go’s minimalist philosophy. Understanding constraints like constraints.Ordered and leveraging generics effectively can greatly enhance code quality and maintainability.&lt;/p&gt;

&lt;p&gt;As generics continue to evolve, they are destined to play a central role in Go’s ecosystem. So, dive in, experiment, and embrace the new era of type safety and flexibility in Go programming!&lt;/p&gt;

&lt;p&gt;Checkout github repository for some samples on generics.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/sadananddodawadakar" rel="noopener noreferrer"&gt;
        sadananddodawadakar
      &lt;/a&gt; / &lt;a href="https://github.com/sadananddodawadakar/GoGenerics" rel="noopener noreferrer"&gt;
        GoGenerics
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repository contains working examples of go generics
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Go Generics: Comprehensive Examples Repository&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Welcome to the &lt;strong&gt;Go Generics Repository&lt;/strong&gt;! This repository is a one-stop resource for understanding, learning, and mastering generics in Go, introduced in version 1.18. Generics bring the power of type parameters to Go, enabling developers to write reusable and type-safe code without compromising on performance or readability.&lt;/p&gt;

&lt;p&gt;This repository contains carefully curated examples that cover a wide range of topics, from basic syntax to advanced patterns and practical use cases. Whether you're a beginner or an experienced Go developer, this collection will help you leverage generics effectively in your projects.&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 What's Inside&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;strong&gt;🔰 Basic Generic Programs&lt;/strong&gt;&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;These examples introduce the foundational concepts of generics, helping you grasp the syntax and core features:&lt;/p&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;strong&gt;GenericMap&lt;/strong&gt;: Demonstrates a generic map function to transform slices of any type.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Swap&lt;/strong&gt;: A simple yet powerful example of swapping two values generically.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;FilterSlice&lt;/strong&gt;: Shows how to filter…&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/sadananddodawadakar/GoGenerics" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>go</category>
      <category>programming</category>
      <category>cloudnative</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Hidden Power of Go: Unveiling the Secrets of a Robust Language</title>
      <dc:creator>Sadanand Dodawadakar</dc:creator>
      <pubDate>Wed, 01 Jan 2025 20:49:20 +0000</pubDate>
      <link>https://dev.to/sadanand_dodawadakar_10b2/hidden-power-of-go-unveiling-the-secrets-of-a-robust-language-29jc</link>
      <guid>https://dev.to/sadanand_dodawadakar_10b2/hidden-power-of-go-unveiling-the-secrets-of-a-robust-language-29jc</guid>
      <description>&lt;p&gt;Golang is celebrated for its simplicity, efficiency, and developer-friendly features. While most developers are familiar with Go’s hallmark features like go-routines, channels, and its standard library, there’s a wealth of hidden power. In this article, we will explore Go’s lesser-known capabilities that can significantly enhance your development process and application performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The runtime Package: A Peek Under the Hood
&lt;/h2&gt;

&lt;p&gt;The runtime package offers a set of tools that allow you to inspect and manipulate Go’s runtime system. It’s not just for debugging; it’s also a window into how Go works.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Go-routine Inspection&lt;/strong&gt;&lt;br&gt;
The &lt;strong&gt;runtime.NumGoroutine&lt;/strong&gt; function provides the current number of goroutines running in your application, useful for monitoring concurrency.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Printf("Number of Goroutines: %d\n", runtime.NumGoroutine())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;*&lt;em&gt;Callers and Callstack *&lt;/em&gt;&lt;br&gt;
Using runtime.Callers and runtime.CallersFrames, you can inspect the call stack programmatically. This is especially useful in debugging complex issues.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime"
)


func printCallers() {
    pc := make([]uintptr, 10)
    n := runtime.Callers(2, pc)
    frames := runtime.CallersFrames(pc[:n])
    for frame, more := frames.Next(); more; frame, more = frames.Next() {
        fmt.Printf("%s\n    %s:%d\n", frame.Function, frame.File, frame.Line)
    }
}

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Manual Garbage Collection:&lt;/strong&gt;&lt;br&gt;
While Go has an automatic garbage collector, you can trigger garbage collection manually using runtime.GC() in scenarios where deterministic cleanup is necessary.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime"
)

func InvokeGC() {
    runtime.GC()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Dynamic Memory Stats:&lt;/strong&gt;&lt;br&gt;
Use runtime.ReadMemStats to gather detailed memory usage statistics, aiding in performance optimisation.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main() 

import (
    "fmt"
    "runtime"
)

func PrintMemStates() {
    var stats runtime.MemStats
    runtime.ReadMemStats(&amp;amp;stats)
    fmt.Printf("Allocated memory: %v KB\n", stats.Alloc/1024)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advanced Debugging with the debug Package
&lt;/h2&gt;

&lt;p&gt;The debug package complements runtime by offering tools for deep runtime diagnostics. It’s especially useful for debugging complex issues in production.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stack Trace Retrieval&lt;/strong&gt;&lt;br&gt;
The debug.Stack function lets you capture stack traces programmatically for logging or monitoring purposes.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime/debug"
)

func main() {
    fmt.Printf("Stack Trace:\n%s\n", debug.Stack())
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Symbolic Metadata&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Access build information, including dependencies and module versions, using debug.ReadBuildInfo. This is invaluable for debugging version mismatches in production.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime/debug"
)

func main() {
    info, ok := debug.ReadBuildInfo()
    if ok {
        fmt.Printf("Build Info:\n%s\n", info.String())
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Memory Management&lt;/strong&gt;&lt;br&gt;
The debug.FreeOSMemory function forces the release of unused memory back to the operating system, which can be a lifesaver in resource-constrained environments.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "runtime/debug"
)

func triggerGCWithFreeOSMemeory() {
    debug.FreeOSMemory
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Embedding Files with embed: Simplified Asset Management
&lt;/h2&gt;

&lt;p&gt;Introduced in Go 1.16, the embed package allows you to include files and directories into your Go binaries, making it easier to distribute standalone applications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "embed"
    "fmt"
)

//go:embed config.json
var configFile string

func main() {
    fmt.Println("Embedded Config:", configFile)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This eliminates the need for external configuration file management during deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build Tags: Conditional Compilation
&lt;/h2&gt;

&lt;p&gt;Go’s build tags allow you to include or exclude files during compilation based on conditions like OS or architecture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// +build linux

package main

import "fmt"

func main() {
    fmt.Println("This code runs only on Linux.")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
      <category>cloudnative</category>
      <category>micro</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
