4 ms·
Why I Like Ruby, Part 2: Blocks
- troygoode 16y agoI too love Ruby and their blocks, but I do have to disagree with Rob's statement that C#'s "block" syntax is "obtuse." Certainly it was in the days of straight-up delegates, but the additions of Func<T>, Action, and anonymous methods have really cleaned that up and made it nice and easy to use. Also, I'm not entirely certain what Rob meant by calling LINQ a "Tinker-Toy syntax". C# example of blocks (loosely based upon Rob's examples): //the action argument is the C# version of a block // - by specifying Action<Artist> I'm stating that the block // - will take 1 parameter, of type Artist public void ParseKey(XDocument doc, string elName, Action<Artist> block) { //using XLinq instead of Nokogiri... *jealous* foreach(var node in doc.Elements(elName)) { var artist = new Artist{ Name = node.Element("Name").Value, ArtistId = (int)node.Element("ArtistId").Value }; block(artist); } } //called by: public void Main() { var doc = XDocument.Load("..\db\artists.xml"); ParseKey(doc, "Artist", artist=>{ //this is an anonymous method, the equiv // of a Ruby block. "artist=>" is the equiv // of |artist| Db.Save(artist); Console.WriteLine(artist.Name); }); } Certainly it is a bit cleaner in Ruby by way of: 1) Nokogiri is super awesome. 2) Ruby's dynamicness means we don't have to have type ceremony everywhere. That said, they're pretty equivalent in terms of functionality and expressiveness to me.
- robconery 16y agoThe "Tinker toy" reference was with respect to anonymouse delegates: var thing () => {//code} I think Anders is going to run out of symbols soon :). The code you write here is fine - but you're tying Artist to the ParseKey method - which is the point of doing the block in the first place (to free that up). This might not look obtuse to you - but it's a lot more code than I have :). Also - please don't forget the tie-in with method_missing; the reason it's nice is you're freeing your calling code from understanding the parser - which I don't think you can do here...
- troygoode 16y agoWhile the lambda pointer is certainly not the prettiest thing in the world, "x=> { CODE }" isn't all that different from "do |x| CODE end". You might prefer one over the other - and perhaps the Ruby one is easier to learn if you learn it first - but I don't think there is a big difference. On the other hand, you're certainly right that the code I wrote is longer than yours. You are also correct that it ties itself to the Artist class, but that was because I was only exercising the use of C#'s version of blocks - not dynamic awesomesauce like method_missing. Method_missing is also possible to do in C# with .Net 4, as I'm sure you know. A more complete rewrite of your example might be along the lines of: //have to inherit from DynamicObject to get special dynamic treatment public class DynamicXmlElement : DynamicObject { private XElement _element; public DynamicXmlElement(XElement element) { _element = element; } //C# 4 equiv of method_missing public override bool TryGetMember(GetMemberBinder binder, out object result) { if(_element.Element(binder.Name) == null) return false; result = _element(binder.Name).Value; return true; } } //changed this to use Action<dynamic> public void ParseKey(XDocument doc, string elName, Action<dynamic> block) { foreach(var node in doc.Elements(elName)) block(new DynamicXmlElement(node)); } public void Main() { var doc = XDocument.Load("..\db\music.xml"); ParseKey(doc, "Artist", artist=>{ Db.SaveArtist(artist.ArtistId, artist.Name); Console.WriteLine(artist.Name); }); ParseKey(doc, "Genre", genre=>{ Db.SaveGenre(genre.GenreId, genre.Name); Console.WriteLine(genre.Name); }); } That said, yes, you can do this with less work/ceremony in Ruby as you've shown. I'm a big fan of Ruby and I'm glad you're showing MS devs what makes it so cool. I just don't want anyone to get the impression that some of these basic things are things that simply cannot be done in C#.
- robconery 16y agoUnfortunately no matter how many times I write that "you can do this in [LANGUAGE]" - people don't see that part :). It's no the doing of it - it's the doing of it well. Cleanly and expressively - that's what I like about Ruby. You have to see in the code you write here...
- troygoode 16y ago