From: Sean Middleditch Date: 2001-08-25T12:14:29+09:00 Subject: [ruby-talk:20348] Re: Backwards language On 25 Aug 2001 10:43:49 +0900, Joel Wilsson wrote: > Hi Sean, > > > Perhaps you have some good examples that'd sway my opinion > > I'm currently writing an ftpd in Ruby, and I've been experimenting > with a few language features (lots of fun :) > I've found that eval is one of the most interesting functions there > is. Here's a snippet (ab)using it. > > ftpmethods = [ ] > @socket.methods.each { |m| > if (m =~ /^ftp_/) and not (m =~ /reply\d+/) > ftpmethods << m.sub(/^ftp_/, "") > end > } > big_case = "case s\n" > ftpmethods.each { |m| > big_case += "when /^#{f}/i\n @socket.ftp_#{f} s.sub(/^#{f} */i, \"\")\n" > } > big_case += "else @socket.ftp_reply502 unless @socket.closed? end" > until socket.closed? > s = @socket.gets unless socket.closed? > eval big_case > end > > @socket has been extended by an FTP command module, which has > functions like ftp_user, ftp_pass, ftp_stor, and an FTP reply > module which has functions like ftp_replyXXX where XXX is a > three-digit reply code (specified by the FTP RFC). > First I loop over @socket's method and add "user", "pass" > etc., and big_case checks the FTP clients reply string to see > if it matches any of the FTP methods supported by @socket. > Instead of having to type out all FTP methods manually, the > wonderful loop takes care of all that. > As an extra bonus I only have to add FTP commands to the FTP > command module and have them work automatically, without > having to add them to the "big case". > Oh, and the FTP reply module is also created by an eval, which > takes a hash of the form "CODE" => "description" and makes a > module out of it. For example: > Now, to me, that looks like a cheap hack. ^,^ I've easily written in C/C++ code that is dependent on data, and the data is only defined in one place. The code is intelligent enough to understand the data. In a language such as Ruby, which is dynamically cast, it should be even easier to find a method name within a class, as I believe you're explaining, if a method exists for doing so (I believe there is). Instead of having a complete eval() implementation including a language parser, a little extra code and the use of a method to find methods in a class by name, which would work perfectly well in an "interpreted" language such as Ruby, would require far less code on the interpreter's end (no need for a compiler to be built in), and IMHO would result in more readable code that is just as powerful and dynamic. I'm still in the process of fully learning Ruby's powerful syntax, but in psuedo code: until socket is closed s = socket.gets m = socket.method ("ftp_" + (s ~ /^\S+/)) if m is valid m s.sub ('^\S+\s+', '') Again, forgive my brain lapse, but I've been working with a few too many languages lately, and Ruby really is one of the newer ones I'm working with. I'm not going to take the time to turn that into real Ruby code, but I'm fairly sure one could do something like that in that short and simple of a matter, assuming the equivalent of a method() method exists (finds a method in the instance that has the given name) > # some replies need arguments, which are aN > "215" => "#{a0} system type." > # Creates the method (in the FTP reply module) > ftp_reply215 (a0) > puts "#{a0} system type.\r\n" > # this is so i can use commands like > # "ftp_reply501 and return unless setup_ok?" > # all reply functions return true > return true > end > > No, the code isn't exactly easy to read, and can get quite > confusing, but I'm not trying to write readable code, I'm > trying to have fun with Ruby (and I AM having lots of fun :) > While these examples may be a bit extreme, I hope you see > how extremely powerful eval() really is. > It's when you go wild with language features you realize how > unique Ruby is. Yes, I see that eval() is very power in the fact that it can dynamically generate executable code, and I believe that it is fun (I love playing with stuff like that myself). But is it really necessary? When one wants a very small runtime that is very fast, is that power worth embedding an entire compiler? And, to be honest, if you're developing a large-scale (possibly commercial grade) application, is fun or robustness/efficiency more important? Some features are fun, and possibly useful, but I still don't at all see eval() as being necessary, or even wise. Sorry. ^,^ Perhaps I'm just too old and set in my ways. > > > Regards,