Crystal: Any plans on runtime class reflection or importing Ruby's class#send method?

Created on 7 Apr 2017  路  8Comments  路  Source: crystal-lang/crystal

For those not familiar with class#send:

class Rubyist
  def welcome(*args)
    "Welcome " + args.join(' ')
  end
end
obj = Rubyist.new
puts(obj.send(:welcome, "famous", "Rubyists"))   # => Welcome famous Rubyists

Since we can already use #responds_to? to do something like:

class Helloworld
  def custom_method
    puts "hi"
  end
end

ex = Helloworld.new
if ex.responds_to?(:custom_method)
    # ...
end

The only problem that I currently see, aside from send as a method name that would break a lot of apps out there, is #responds_to? doesn't support Symbol types that aren't explicitly written directly into the parameter as a symbol for example:

class Hello
end

example = Hello.new

# works
if example.responds_to?(:example)
end


stored = {} of String => Symbol
stored["example"] = :example

puts typeof(stored["example"]) # => Symbol

### below will spit out: 
###    'Syntax error in eval:9: unexpected token: stored (expected symbol)' 
### despite the type being a symbol

# not possible
# if example.responds_to?(stored["example"])
# end

Also @asterite talks about a few faults regarding a #send method such as:

1. You have to include a class/methods table in the executable to be able to search it for runtime execution.
2. Since methods in Crystal are instantiated when you use them, if you don't use a method then it won't appear in the executable.

But that's pretty much solved with #responds_to? so I don't think it's a problem now that the language is much mature aside from the issue I brought up previously w/ passing stored symbol values to the responds_to method not being possible.

With that said, I'd really _love_ this feature added to crystal or some form of class reflection and I could comfortably move over to crystal from php as my main language once we get closer to 1.0.

Most helpful comment

Adding send will open the door for "I will implement everything with send because I can", making all code in most shards just be fragile and slow. If there isn't a real use case for this other than "less code to write at the cost of slower runtime execution and unexpected behaviour" then chances of us implementing this are basically zero. Add to that the fact that, reasons mentioned above, it would be super hard to implement it, probably impossible.

All 8 comments

Since this is already getting down-votes, now I'm curious to why some of you don't want this as a feature?

@exts Because it would be prohibitively difficult (impossible without changing language semantics) to implement, for the exact reason you mention in your issue

Since methods in Crystal are instantiated when you use them, if you don't use a method then it won't appear in the executable.

@exts Is there a current use case that you can't cover with the current language and you need send for it?

@asterite is there a use case that I can't cover w/ the current language that send is required? _no_, it'd just cut down a lot of code to a few lines for reasons that I'd use it for personally, more for convenience purposes.

Adding send will open the door for "I will implement everything with send because I can", making all code in most shards just be fragile and slow. If there isn't a real use case for this other than "less code to write at the cost of slower runtime execution and unexpected behaviour" then chances of us implementing this are basically zero. Add to that the fact that, reasons mentioned above, it would be super hard to implement it, probably impossible.

@asterite alright

@exts FWIW do you have a more specific use case? Maybe we can help you compress it a little or something... ;)

@kirbyfan64 no offense to the core dev on mustafa, but in this example you're kind of forced to write unnecessary boilerplate to accomplish what he's doing here because something like #send doesn't exist in crystal. Another method to accomplish a similar goal is how I'm doing it in my micro-framework.

Here I'm forced to create an 'action' method if I want to have true controllers that aren't single actions which I managed to do here. My original goal was to be able to do exactly what I'm currently doing except I wouldn't need to have an action factory method (i could even create a factory class which refactors this bit out, but it seems unnecessary) to call dynamic routes.

You can look in the readme for an example of the goal I had in mind for my micro-framework.

Regardless, it's impossible to implement within the current code base based on the responses above. I like crystal, but you have to work a little harder to accomplish a few things :)

Was this page helpful?
0 / 5 - 0 ratings