Generics in Ruby

Ruby doesn’t have built-in support for generics like Go does. However, we can achieve similar functionality using Ruby’s dynamic typing and duck typing. Here’s how we can implement similar concepts:

# As an example of a method that works with any enumerable,
# 'slices_index' takes an enumerable and a value, and returns
# the index of the first occurrence of v in s, or -1 if not present.
def slices_index(s, v)
  s.each_with_index do |item, index|
    return index if item == v
  end
  -1
end

# As an example of a flexible data structure,
# 'List' is a singly-linked list that can hold values of any type.
class List
  def initialize
    @head = nil
    @tail = nil
  end

  def push(v)
    if @tail.nil?
      @head = @tail = Element.new(v)
    else
      @tail.next = Element.new(v)
      @tail = @tail.next
    end
  end

  def all_elements
    elements = []
    current = @head
    while current
      elements << current.val
      current = current.next
    end
    elements
  end

  private

  class Element
    attr_accessor :next, :val

    def initialize(val)
      @val = val
      @next = nil
    end
  end
end

# Main execution
s = ["foo", "bar", "zoo"]

# When calling 'slices_index', we don't need to specify types
# as Ruby is dynamically typed
puts "index of zoo: #{slices_index(s, "zoo")}"

# Create and use a List
lst = List.new
lst.push(10)
lst.push(13)
lst.push(23)
puts "list: #{lst.all_elements}"

To run the program:

$ ruby generics.rb
index of zoo: 2
list: [10, 13, 23]

In this Ruby version, we’ve implemented similar functionality to the Go example:

  1. The slices_index method works with any enumerable object, similar to the generic SlicesIndex function in Go.

  2. The List class can store elements of any type, similar to the generic List struct in Go.

  3. We don’t need to explicitly declare types as Ruby is dynamically typed, which provides flexibility similar to generics in some cases.

  4. The push and all_elements methods work similarly to their Go counterparts.

While Ruby doesn’t have a direct equivalent to Go’s generics, its dynamic nature and duck typing often allow for writing flexible code that works with multiple types without needing explicit type parameters.