Reputation: 7326
I like eval
in Ruby because it works pretty straightforward:
eval("puts 7 * 8") # => 56
What is an eval
's equivalent in Crystal ? I know that we can do something similar with macro:
macro eval(code)
{{code.id}}
end
eval("puts 7 * 8") # => 56
But this won't work with runtime values:
a = "yo"
eval("puts #{a}") # => prints nothing
Upvotes: 5
Views: 1343
Reputation: 828
waj, one of the developers of the Crystal language, wrote in 2015
because that would imply that your compiled program includes the Crystal compiler built in and it actually doesn't make much sense.
But, including the interpreter in the executable may not be such a crazy idea in 2022. Anyolite can include mruby or CRuby in the executable.
https://github.com/Anyolite/anyolite
kitty.cr
require "anyolite"
code = ARGV[0]
class Kitty
def initialize(@n : Int32)
end
def mew
puts "mew " * @n
end
end
Anyolite::RbInterpreter.create do |rb|
Anyolite.wrap(rb, Kitty)
Anyolite.eval(code)
end
build:
crystal build kitty.cr
run:
./kitty "Kitty.new(3).mew"
output:
mew mew mew
The generated executable is about 7MB larger (probably because it contains mruby). However, that is not a problem considering the advantage of being able to eval with Crystal. Yes, eval may be a bad practice. But I think there are cases where it can be very useful.
Upvotes: 1
Reputation: 1185
Crystal is a compiled language, while Ruby is interpreted. That makes evaluating code at runtime much more complicated.
In your example, the macro is expanded at compile time, so actually your program is just puts 7 * 8
. In other words, it works because the code is known at compile time.
But if you wanted to execute the code contained in an arbitrary string, it would have to invoke the Crystal compiler and then execute the resulting executable. This is actually something we do in the Crystal unit tests. But there is no "eval" function included in the standard library because that would imply that your compiled program includes the Crystal compiler built in and it actually doesn't make much sense.
Another problem is how to pass arguments and take return values. Since the program you're running and the evaluated code are the result of different compilations, they might have different binary representations of the same types.
On the other hand, using eval
in Ruby is usually known as a bad practice and must be avoided if possible.
Upvotes: 15