Extension Methods in Crystal

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

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 ;-).

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

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

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

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


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

Elixir’s pipe operator has been proposed and refused:

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

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.

1 Like

That syntax variant hasn’t gotten a lot of traction in ruby-land though, so I hope we don’t import it :slight_smile:. 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 newerit 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.

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

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:

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

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

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

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.

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


[{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.

1 Like

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!

2 Likes