name: crystal-lang description: "Use this skill when working with the Crystal programming language. Crystal is a statically-typed, compiled language with Ruby-like syntax. It features type inference, null safety, macros, and compiles to efficient native code. Use for understanding Crystal's standard library, syntax, semantics, concurrency model, and FFI bindings."
Crystal-Lang Skill
Use this skill when working with the Crystal programming language. a statically-typed, compiled language with Ruby-like syntax that combines Ruby's coding efficiency with C's runtime performance.
When to Use This Skill
This skill should be triggered when:
- Writing Crystal code and need syntax, semantic, or API guidance
- Debugging Crystal compilation errors or runtime issues
- Understanding Crystal's type system, type inference, or union types
- Working with Crystal's concurrency model (fibers, channels, spawn)
- Using Crystal macros for metaprogramming and compile-time code generation
- Interfacing with C libraries via FFI bindings
- Implementing web services with the Crystal standard library (HTTP, HTTPS, WebSocket)
- Processing data formats (JSON, XML, YAML, CSV)
- Working with Crystal's standard library APIs
Key Concepts
Type System
- Type Inference: The compiler infers types without explicit annotations in most cases
- Union Types: Variables can have multiple possible types at compile time (e.g.,
Int32 | String) - Null Safety: Nilable types (
String?) must be checked before use - Generic Types: Reusable code with type parameters (e.g.,
Array(T),Hash(K, V))
Concurrency Model
- Fibers: Lightweight cooperative threads scheduled by the runtime
- Channels: Communication primitives for passing data between fibers
- spawn: Create a new fiber for concurrent execution
Macros
- Compile-time Execution: Macros run during compilation, not at runtime
- AST Manipulation: Modify and generate code programmatically
- Flag-based Compilation: Conditional code based on compile-time flags
Quick Reference
Basic Syntax
Hello World
# hello.cr
puts "Hello, World!"
Variables and Types
name = "Crystal" # : String
count = 42 # : Int32
pi = 3.14 # : Float64
enabled = true # : Bool
nothing = nil # : Nil
# Type annotations work too
x : Int32 = 10
String Interpolation
name = "World"
puts "Hello, #{name}!" # => Hello, World!
Methods and Blocks
Defining Methods
def greet(name : String) : String
"Hello, #{name}!"
end
def add(x : Int32, y : Int32) : Int32
x + y
end
Default Arguments
def greet(name : String, enthusiastic : Bool = false)
message = "Hello, #{name}"
enthusiastic ? "#{message}!" : message
end
Blocks and Procs
# Using a block
[1, 2, 3].map { |x| x * 2 } # => [2, 4, 6]
# Short syntax
[1, 2, 3].map(&.to_s) # => ["1", "2", "3"]
# Storing a block
double = ->(x : Int32) { x * 2 }
double.call(5) # => 10
Control Flow
If/Else
if count > 0
puts "Positive"
elsif count < 0
puts "Negative"
else
puts "Zero"
end
# Ternary
result = count > 0 ? "positive" : "non-positive"
Case/When
case value
when 1, 2, 3
puts "Small"
when 4..10
puts "Medium"
else
puts "Large"
end
Unless
puts "Access denied" unless user.logged_in?
Classes and Structs
Class Definition
class Person
property name : String
property age : Int32
def initialize(@name : String, @age : Int32)
end
def greet : String
"Hi, I'm #{@name}, #{@age} years old"
end
end
person = Person.new("Alice", 30)
person.greet # => "Hi, I'm Alice, 30 years old"
Inheritance
class Employee < Person
def initialize(@name : String, @age : Int32, @title : String)
super(@name, @age)
end
end
Structs for Value Types
struct Point
property x : Float64
property y : Float64
def initialize(@x : Float64, @y : Float64)
end
end
Collections
Arrays
# Literal
numbers = [1, 2, 3, 4, 5]
# Operations
numbers << 6 # append
numbers.first # => 1
numbers.last # => 5
numbers.size # => 5
numbers.includes?(3) # => true
numbers.map { |x| x * 2 } # => [2, 4, 6, 8, 10]
Hashes
# Literal
scores = {"Alice" => 100, "Bob" => 95}
# Access
scores["Alice"] # => 100
scores["Charlie"]? # => nil (safe access)
scores.fetch("Dave", 0) # => 0 (default)
Ranges
1..10 # inclusive range
1...10 # exclusive range
('a'..'z').to_a.first(3) # => ['a', 'b', 'c']
Union Types and Nilable Types
Union Types
def process(value : Int32 | String)
# Methods must exist for ALL types in the union
value.to_s
end
Nilable Types
def find_user(id : Int32) : User?
# Returns User or nil
users.find { |u| u.id == id }
end
user = find_user(1)
if user
puts user.name # user is guaranteed non-nil here
end
# Safe navigation
name = user&.name || "Unknown"
Type Narrowing
value = rand > 0.5 ? 42 : "hello"
if value.is_a?(Int32)
value.abs # Compiler knows value is Int32 here
else
value.size # Compiler knows value is String here
end
Exception Handling
Begin/Rescue/Ensure
begin
File.read("nonexistent.txt")
rescue ex : FileNotFoundError
puts "File not found: #{ex.message}"
rescue ex : Exception
puts "Error: #{ex.message}"
ensure
puts "Cleanup code runs here"
end
Custom Exceptions
class MyError < Exception
end
raise MyError.new("Something went wrong")
Concurrency
Spawning Fibers
spawn do
puts "Running in background"
sleep 1
puts "Done"
end
puts "Main continues"
Fiber.yield # Let other fibers run
Channels
channel = Channel(Int32).new
spawn do
channel.send(42)
end
result = channel.receive # Blocks until value is available
puts result # => 42
Async Operations
def fetch_data : String
"data"
end
# Non-blocking with spawn
spawn { puts fetch_data }
Fiber.yield
Macros
Compile-time Execution
# Run shell command at compile time
{% `echo "compiled at build time"` %}
# Check compile-time flags
{% if flag?(:x86_64) %}
puts "Running on 64-bit architecture"
{% end %}
Macro Methods
macro define_method(name, content)
def {{name}}
{{content}}
end
end
define_method(:greet, puts "Hello from macro!")
Reading Files at Compile Time
# Embed file contents at compile time
VERSION = {{ read_file("VERSION.txt").strip }}
File I/O
Reading Files
# Read entire file
content = File.read("file.txt")
# Read line by line
File.each_line("file.txt") do |line|
puts line
end
# Check file exists
if File.exists?("file.txt")
puts "File exists"
end
Writing Files
# Write string to file
File.write("output.txt", "Hello, File!")
# Append to file
File.open("log.txt", "a") do |file|
file.puts "Log entry"
end
JSON Processing
Parsing JSON
require "json"
data = JSON.parse(%({"name": "Alice", "age": 30}))
data["name"].as_s # => "Alice"
data["age"].as_i # => 30
Generating JSON
require "json"
hash = {"name" => "Bob", "age" => 25}
JSON.build do |json|
json.object do
json.field "name", hash["name"]
json.field "age", hash["age"]
end
end
JSON Mapping
require "json"
class User
include JSON::Serializable
property name : String
property age : Int32
end
user = User.from_json(%({"name": "Charlie", "age": 35}))
user.to_json # => %({"name":"Charlie","age":35})
HTTP Client
Simple GET Request
require "http"
response = HTTP.get("https://api.example.com/data")
puts response.status_code # => 200
puts response.body
POST with JSON Body
require "http"
response = HTTP.post("https://api.example.com/users",
headers: {"Content-Type" => "application/json"},
body: %({"name": "Dave"}).to_json
)
HTTP Client with Persistent Connection
require "http"
client = HTTP::Client.new("https://api.example.com")
response = client.get("/endpoint")
client.close
XML Processing
Parsing XML
require "xml"
xml = <<-XML
<person id="1">
<firstname>Jane</firstname>
<lastname>Doe</lastname>
</person>
XML
document = XML.parse(xml)
person = document.first_element_child
if person
puts person["id"] # => "1"
puts person.content # => "Jane"
end
Building XML
require "xml"
string = XML.build(indent: " ") do |xml|
xml.element("person", id: 1) do
xml.element("firstname") { xml.text "Jane" }
xml.element("lastname") { xml.text "Doe" }
end
end
C Bindings (FFI)
Declaring External Library
lib LibC
fun strlen(s : UInt8*) : SizeT
end
# Call C function
LibC.strlen(pointer)
C Linking
@[Link("pcre")]
lib LibPCRE
fun pcre_compile(pattern : UInt8*) : Pointer(Void)
end
Pointer Operations
x = 1
ptr = pointerof(x)
ptr.value = 2
puts x # => 2
# Allocated memory
ptr = Pointer.malloc(2, 42)
ptr[0] # => 42
ptr[1] # => 42
BitArray
require "bit_array"
ba = BitArray.new(12) # => "BitArray[000000000000]"
ba[2] # => false
0.upto(5) { |i| ba[i * 2] = true }
ba # => "BitArray[101010101010]"
ba[2] # => true
Union Type Operations
# Union simplification
Union(Int32 | String) # => (Int32 | String)
Union(Int32) # => Int32
Union(Int32, Int32, Int32) # => Int32
Weak References
require "weak_ref"
ref = WeakRef.new("oof".reverse)
p ref # => #<WeakRef(String):...>
GC.collect
p ref # => #<WeakRef(String):... @target=Pointer.null>
p ref.value # => nil
Reference Files
This skill includes comprehensive documentation in references/:
Getting Started (getting_started.md)
- Source: Official Crystal documentation (medium confidence)
- Pages: 2 (Language Introduction, About this guide)
- Content: Beginner-friendly introduction to Crystal's core concepts
Standard Library (standard_library.md)
- Source: Official Crystal API documentation (medium confidence)
- Pages: 265 (extensive API coverage)
- Topics:
- Core types: Union, WeakRef, Pointer, BitArray
- I/O operations: XML, JSON, compression, hexdump
- Networking: HTTP, HTTPS, WebSocket, OpenSSL
- System: GC stats, event loop, LLVM integration
- Standard library utilities
Syntax and Semantics (syntax_and_semantics.md)
- Source: Official Crystal language reference (medium confidence)
- Pages: 351 (comprehensive language specification)
- Topics:
- Crystal::Macros module for compile-time metaprogramming
- Event loop and concurrency primitives
- Type system details (generics, unions, nilable types)
- Inheritance and type relationships
- C bindings and FFI
- Language semantics and features
Working with This Skill
For Beginners
- Start with the Getting Started reference for language introduction
- Review the basic syntax examples in the Quick Reference above
- Practice with simple programs before moving to advanced topics
For Intermediate Users
- Use Syntax and Semantics for understanding type system details
- Reference the Standard Library for available APIs
- Explore macros for compile-time code generation
For Advanced Users
- Dive into C bindings for performance-critical code
- Study concurrency patterns with fibers and channels
- Use advanced macro techniques for metaprogramming
Navigation Tips
- Search reference files using the "URL:" markers to locate specific API docs
- Code examples include language tags for syntax highlighting
- Macro examples use
{% %}for compile-time code - Type annotations use
# : TypeNamecomments
Resources
Official Documentation
Community
- Crystal Forum
- Gitter channel
- IRC: #crystal-lang at irc.libera.chat
- Stack Overflow: crystal-lang tag
- GitHub: crystal-lang/crystal
Notes
- This skill synthesizes knowledge from official Crystal documentation
- Documentation version: 1.18
- Crystal prioritizes backward compatibility within major versions
- The language is statically-typed but with powerful type inference
- Compile-time macros enable zero-cost abstractions
Updating
To refresh this skill with updated documentation:
- Re-run the documentation scraper
- The skill will be rebuilt with the latest information from official sources