# Extension Methods in Crystal

**URL:** <https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323>\
**Category:** Community\
**Created:** [August 8, 2025, 12:30pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323 "2025-08-08T12:30:54Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Haddock](https://avatars.discourse-cdn.com/v4/letter/h/e9bcb4/32.png) [@Haddock](https://forum.crystal-lang.org/u/Haddock)\
**Post date:** [August 8, 2025, 12:30pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/1 "2025-08-08T12:30:54Z")

</div>

I’m new to Crystal and from what I’ve seen so far Crystal does not have them like Ruby.

Java does not have them, either. This has resulted in Java in tons of static helper methods being created in separate utility classes, which is quite annoying as it breaks OO thinking and you have to know by heard about all those static utility methods and where the are located.

The D programming language has the so called Uniform Function Call Syntax, see [Uniform Function Call Syntax (UFCS) - Dlang Tour](https://tour.dlang.org/tour/en/gems/uniform-function-call-syntax-ufcs)

So “foo(bar(a))” could also be written as “a.bar().foo()“

My question is whether that would be an idea for Crystal as well. Maybe it would not be that hard to tweak the Crystal compiler to implement a similar solution. I don’t know - just a question ;-).

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [August 8, 2025, 12:52pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/2 "2025-08-08T12:52:40Z")

</div>

In 2019, Ruby tried adding a pipeline operator (`|>`), but it was not accepted in the end.

[https://bugs.ruby-lang.org/issues/15799](https://bugs.ruby-lang.org/issues/15799)

Ruby uses `then/yield_self`, but these are not available in Crystal.

[https://bugs.ruby-lang.org/issues/17353](https://bugs.ruby-lang.org/issues/17353)

```rb
gets.to_i
  .then(&method(:make_stuff))
  .then { format "the number is %d", _1 }
  .then(&method(:puts))

```

---

<div class="post-metadata">

**Author:** ![aiac](https://avatars.discourse-cdn.com/v4/letter/a/db5fbb/32.png) [@aiac](https://forum.crystal-lang.org/u/aiac)\
**Post date:** [August 8, 2025, 2:21pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/3 "2025-08-08T14:21:04Z")

</div>

I don’t know if this is what you want.

```crystal

module StringExt
  def name_and_ext
    self.split "."
  end
end

class String
  include StringExt
end

name, ext = "hello.cr".name_and_ext
p! name
p! ext

```

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [August 8, 2025, 4:23pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/4 "2025-08-08T16:23:44Z")

</div>

Elixir’s pipe operator has been proposed and refused:

> <https://github.com/crystal-lang/crystal/issues/1388>
>
> It would be great if Crystal had a construct similar to \[Elixir's pipe operator\]…(http://elixir-lang.org/docs/v1.0/elixir/Kernel.html#%7C%3E/2) \`|\>\`:
> 
> \`\`\` crystal
> class Importer
> def import(io)
> xml = parse\_xml(io)
> root = find\_root\_node(xml)
> tree = build\_tree(root)
> end
> 
> def import2(io)
> io |\> parse\_xml |\> find\_root\_node |\> build\_tree
> end
> end
> \`\`\`
> 
> I think that the latter example is much easier to read and requires far less eye tracking to comprehend.
> 
> The implementation in Elixir is simply syntactic sugar using a macro, not sure if Crystal's macros could do this transform as well.
> 
> This has been briefly discussed in #1099, but I don't think the arguments against it were valid. Crystal is just like Ruby a hybrid between an OO and functional language and I really like the funtional core, imperative shell pattern, which leads to well testable units by avoiding shared/hidden state.

You should use explicit chaining (i.e. return `self`). Or maybe monkeypatch `Object.then` as one of the comment there explained.

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [August 8, 2025, 4:27pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/5 "2025-08-08T16:27:59Z")

</div>

Now, this experimental PR got closed, but we’re not against reviving it if someone has the courage to draft a RFC and identifies all the potential issues and what we should disallow.

> <https://github.com/crystal-lang/crystal/pull/9218>
>
> \*\*Note:\*\* Like before, I wanted to see how hard this was to implement. Nothing i…s decided yet.
> 
> Alternative to #9216
> 
> This PR lets you specify a block argument with references to block arguments. \`&1\` is the first block argument, \`&2\` is the second, and so on.
> 
> For example:
> 
> \`\`\`crystal
> \[1, 2, 3\].each &puts(&1)
> \`\`\`
> 
> The above is the same as:
> 
> \`\`\`crystal
> \[1, 2, 3\].each { |x| puts(x) }
> \`\`\`
> 
> You can use \*\*any\*\* expression after \`&\`. For example:
> 
> \`\`\`crystal
> \[1, 2, 3\].map &(&1 \* 2) # =\> \[2, 4, 6\]
> \[1, 2, 3\].map &{&1, &1 \* 10} # =\> \[{1, 10}, {2, 20}, {3, 30}\]
> \[1, 2, 3\].map &\[&1\] # =\> \[\[1\], \[2\], \[3\]\]
> 
> \["foo.cr", "bar.cr"\].map &File.exists?(&1)
> 
> \["World", "Computer"\].each &puts("OK #{&1}")
> \# Output:
> \# OK World
> \# OK Computer
> 
> record Point, x : Int32, y : Int32
> \[{1, 2}, {3, 4}\].map &Point.new(&1, &2) # =\> \[Point(@x=1, @y=2), Point(@x=3, @y=4)\]
> \`\`\`
> 
> Since you can use \*\*any\*\* expression, this is valid too:
> 
> \`\`\`crystal
> \# Not advised... if we really wanted we could disallow this
> \[1, 2, 3\].each &begin
> puts &1
> end
> \`\`\`
> 
> \## Do I like it?
> 
> I think I like it better than #9216 because:
> \- \`&1\`, \`&2\`, etc. are clearly surrounded by \`&...\`
> \- unless you use \`begin\`, or if we disallow it, the things you can put inside are pretty limited, so the block will end up being short and understandable
> \- no need to write \`do/end\` nor \`{ ... }\` so it's actually shorter than the alternative:
> \`\`\`crystal
> \["foo.cr", "bar.cr"\].map &File.exists?(&1) # shorter, simpler
> \["foo.cr", "bar.cr"\].map { File.exists?(&1) }
> \`\`\`
> 
> 
> This is exactly the same in Elixir... except that in Elixir you can use \`&(...)\` in general to create functions, but in this PR you can only use it in a block argument.
> 
> \## What happens with regular block arguments?
> 
> They still work! For example:
> 
> \`\`\`crystal
> proc = -\>(x : Int32) { puts x }
> \[1, 2, 3\].each &proc
> \`\`\`
> 
> The rule is that if there's \`&1\`, \`&2\`, etc. inside the block argument, then it gets expanded to a block. Otherwise it's just forwarded as a block argument. Because the type of the block argument needs to be a \`Proc\`, you will, in most if not all cases, get a compiler error if you try to misuse it. For example:
> 
> \`\`\`crystal
> p \[1, 2, 3\].map &puts("hello")
> ^---
> Error: expected a function type, not Nil
> \`\`\`
> 
> And we can improve the error above saying "If using the short block syntax, be sure to use one of &1, &2, etc." (this PR doesn't do that yet, but it's super easy to implement).
> 
> Another alternative is to restrict the block argument to:
> \- a variable
> \- a proc literal (like \`&-\>File.exists?(String)\`)
> \- anything else, but it must include \`&1\`, \`&2\`, etc, otherwise it's an error
> 
> That alternative is probably better because we can give better error messages.
> 
> \## Implementation details
> 
> For #9216 the first idea that came to my mind for implementing it is:
> \- before analyzing a call's block, check if it has \`&1\`, \`&2\`, etc
> \- if so, add missing block arguments, etc.
> 
> This means that the compiler has to do this for \*\*every block\*\* out there. I'm sure there are more optimal ways to implement this: for example we could detect at parse time which blocks need expansions. But this requires a bit more tracking.
> 
> In this PR we need to do the same, but only for block arguments (\`&...)\`, not for every block. And usually block arguments are just a forwarded variable, or a more complex expression which, with this PR, it's very likely to include these \`&1\` thingies. So the implementation is much more performant.
> 
> \## Final thoughts
> 
> I think this solves the missing use case of short block syntaxes where one would like to put the first argument in a position other than the caller. And it also generalizes it for any number of arguments. All of this being kept surrounded by \`&\` so the code becomes easier to understand.
> 
> /cc @waj

---

<div class="post-metadata">

**Author:** ![yxhuvud](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/yxhuvud/32/27_2.png) [@yxhuvud](https://forum.crystal-lang.org/u/yxhuvud)\
**Post date:** [August 8, 2025, 6:08pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/6 "2025-08-08T18:08:25Z")

</div>

That syntax variant hasn’t gotten a lot of traction in ruby-land though, so I hope we don’t import it 🙂. The upside of being a bit behind ruby syntax wise is after all that we can see what gets used and what doesn’t.

What seems to actually get traction is the even newer`it` as an implicit block parameter so you can do stuff like `[1,2,3].each { puts it }`. That one would be pretty sweet, but I don’t know how hard it would be to make it into the compiler and have the type system be happy.

I also see `then` now and then but I’m on the fence if the usages actually make the code nicer.

---

<div class="post-metadata">

**Author:** ![Sija](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sija/32/737_2.png) [@Sija](https://forum.crystal-lang.org/u/Sija)\
**Post date:** [August 8, 2025, 6:11pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/7 "2025-08-08T18:11:52Z")

</div>

> [@ysbaddaden](#):
>
> Now, this experimental PR got closed, but we’re not against reviving it if someone has the courage to draft a RFC and identifies all the potential issues and what we should disallow.

I’d love to see this one implemented! It’s one of the syntactic sugar bits I’m missing from Elixir so much…

---

<div class="post-metadata">

**Author:** ![Drogoslaw](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/drogoslaw/32/2536_2.png) [@Drogoslaw](https://forum.crystal-lang.org/u/Drogoslaw)\
**Post date:** [August 9, 2025, 1:27am UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/8 "2025-08-09T01:27:36Z")

</div>

> [@yxhuvud](#):
>
> What seems to actually get traction is the even newer`it` as an implicit block parameter so you can do stuff like `[1,2,3].each { puts it }`. That one would be pretty sweet, but I don’t know how hard it would be to make it into the compiler and have the type system be happy.

I don’t know anything about that new `it` thing, but Ruby has had support for unnamed block parameters (`_1`, `_2`, etc.) for quite some time now:

```ruby
[1,2,3].each { puts _1 }

```

Without a doubt, `it` looks better and matches the natural-language-like feel of Ruby way more, though.

---

<div class="post-metadata">

**Author:** ![aiac](https://avatars.discourse-cdn.com/v4/letter/a/db5fbb/32.png) [@aiac](https://forum.crystal-lang.org/u/aiac)\
**Post date:** [August 9, 2025, 4:07am UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/9 "2025-08-09T04:07:08Z")

</div>

I know what you want, and Clojure has better threading macros

> **[Clojure - Threading Macros Guide](https://clojure.org/guides/threading_macros)**

---

<div class="post-metadata">

**Author:** ![yxhuvud](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/yxhuvud/32/27_2.png) [@yxhuvud](https://forum.crystal-lang.org/u/yxhuvud)\
**Post date:** [August 9, 2025, 7:01am UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/10 "2025-08-09T07:01:57Z")

</div>

By “hasn’t gotten a lot of traction” I meant that it exists and people don’t use it much. `it` as an anonymous parameter seems to be used a lot more.

---

<div class="post-metadata">

**Author:** ![Barney](https://avatars.discourse-cdn.com/v4/letter/b/48db29/32.png) [@Barney](https://forum.crystal-lang.org/u/Barney)\
**Post date:** [August 9, 2025, 9:05am UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/11 "2025-08-09T09:05:02Z")

</div>

Similarly, if you’re passing 2 parameters to a method, you might as well just do

```cr

[{1, 2}, {3, 4}].each do |_1, _2|

end

```

and make your intent clearer.

IMO the main use case would be the case of 1 block parameter, where `it` is a lot nicer.

---

<div class="post-metadata">

**Author:** ![Haddock](https://avatars.discourse-cdn.com/v4/letter/h/e9bcb4/32.png) [@Haddock](https://forum.crystal-lang.org/u/Haddock)\
**Post date:** [August 10, 2025, 9:24pm UTC](https://forum.crystal-lang.org/t/extension-methods-in-crystal/8323/12 "2025-08-10T21:24:29Z")

</div>

Thanks, aiac. Just tried it and it worked. My first Crystal program ;-). I had not thought that a system class could that easily be extended thinking a system class must be locked. Now I’m happy!
