Generics in Crystal
Crystal supports generics, which allow you to write flexible, reusable code that works with different types.
# As an example of a generic function, `slices_index` takes
# a slice of any comparable type and an element of that
# type and returns the index of the first occurrence of
# v in s, or -1 if not present.
def slices_index(s, v)
s.index(v) || -1
end
# As an example of a generic type, `List` is a
# singly-linked list with values of any type.
class List(T)
@head : Node(T)?
@tail : Node(T)?
private class Node(T)
property next : Node(T)?
property value : T
def initialize(@value : T)
end
end
# We can define methods on generic types just like we
# do on regular types.
def push(v : T)
new_node = Node.new(v)
if @tail.nil?
@head = @tail = new_node
else
@tail.not_nil!.next = new_node
@tail = new_node
end
end
# all_elements returns all the List elements as an array.
def all_elements
elements = [] of T
current = @head
while current
elements << current.value
current = current.next
end
elements
end
end
# Main function to demonstrate the usage
def main
s = ["foo", "bar", "zoo"]
# When invoking generic functions, Crystal can often infer
# the types automatically.
puts "index of zoo: #{slices_index(s, "zoo")}"
lst = List(Int32).new
lst.push(10)
lst.push(13)
lst.push(23)
puts "list: #{lst.all_elements}"
end
mainTo run the program, save it as generics.cr and use the crystal command:
$ crystal generics.cr
index of zoo: 2
list: [10, 13, 23]In this Crystal version:
We’ve implemented
slices_indexusing Crystal’s built-inindexmethod, which returnsnilif the element is not found. We use the||operator to return -1 in that case.The
Listclass is implemented as a generic type. In Crystal, we use(T)to declare a generic type parameter.Crystal uses
?to denote nullable types, so@headand@tailare declared asNode(T)?.We’ve implemented the
pushandall_elementsmethods similarly to the original example.In the
mainfunction, we demonstrate the usage of both the generic function and the generic type.Crystal can infer types in many cases, so we don’t need to explicitly specify types when calling
slices_indexor creating aList(Int32).
Crystal’s syntax for generics is similar to that of other languages, making it easy to write reusable code that works with different types.