I had a bit of a meltdown on Twitter the other day… well, it wasn’t really a meltdown, it was just frustration. Frustration with C# and desperately wanting a language which allows me to work without a lot of the ceremony that comes with most strongly typed languages. For a while I thought IronRuby was going to help me achieve the goal of moving off C# at least for my web development. I thought that once I got full IronRuby support inside of ASP.NET MVC, bam! That would have been it, I would have used it, no question about it. Alternatively, if I had gotten full Ruby support, I would have also had the option of moving to Rails which makes for interesting conspiracy theories about the downsizing of the IronRuby team.
I got myself pretty upset, I even stayed up until about 2 in the morning on Thursday night writing a long blog post. I’m glad I slept on it for a few days and talked to half a dozen people about it. It made me realize that I didn’t really have any good goals for the post other than to burn off some steam. I thought for a while about what my goals should be, and I thought back to the conversation I had on Twitter. Many of the comments that I received were along the lines of “stop complaining about C#, show me why Ruby is better!” I was actually surprised that I got this comment several times. I mean, everyone knows Ruby,right? (Was that elitist enough for you?)
So, I realized that my goals were really to explain why I am frustrated with C#, and why I think that Ruby (or a Ruby-like language) would make my life easier. I also don’t want you to think that I am saying that C# sucks, I’m not saying that at all. C# is a great language with goals that were different from the highly testable, abstracted, dependency injected world in which we live now. Developers (or at least many developers) on the Microsoft platform *need* a more malleable and flexible language, one which is a first class citizen in the ecosystem. If Microsoft developers don’t get this, then the string of defections to other platforms won’t end any time soon. So, before you fall asleep, let’s get on with the show…
Yes, I Can Invoke Methods On Classes!
No, no you can’t. You invoke methods on objects. Remember, objects and classes aren’t the same thing. You create methods in a class, and then you create an object from that class, then you call methods on that object. But what if you could call methods on classes? What if a class was an object? Would that mean that a class had state? Why yes, yes it would.
Sound useful? No? Well, do you use attributes in C#? What if I told you that you could get some of that exact same functionality in Ruby without tacking on a language feature? What about properties? Ruby does the same thing, without a separate language feature. Check out the following class:
class MyClass include ActiveModel::Validations validates_presence_of :name attr_accessor :name end
A lot going on there. For now we will ignore the “include” line and we will just say that it is a library which allows you to perform validations. Next we see the “validates_presence_of :name”, which as you can probably guess validations the name “property” which is defined below it. (It isn’t really a property, but we will pretend it is for right now) The interesting thing is that both of those are just method calls on the current class. “attr_accessor” is just a method class which creates a getter and setter method called “name”. The method “validates_presence_of” is executed on the class and saves a piece of state which will check to make sure that “name” property has a valid when “valid?” is called on the object.
Pretty powerful stuff… think about how annoying it is in order to create a System.ComponentModel.DataAnnotations validator in .NET which compares two properties? No problem here, we would just pass both properties to a validator method. The flexibility is pretty amazing. Think of all of the uses that you have for attributes, and then think about what it would be like if they could store state, add methods, be combined, etc… It truly is attributes on steroids.
If Only This Class Had A <blank> Method!
We’ve all seen it a hundred times. There is this class you have to use, but it just doesn’t provide the functionality that you want. In C# 3.0 extension methods were introduced that help with this problem immensely, but there are still a few key limitations to their uses. Mainly the fact that they have to be implemented as a static method, which means that they are limited in the scope of what they can accomplish, mainly because they can neither affect the internal state of a type, and because they are unable to apply additional state to an instance. In other words, they can’t add additional “stuff” to a class, they can only interact with its public methods and properties.
So, why not just subclass a type? Well, unfortunately for many types (especially those within the .NET framework) this is impossible. There are tons of sealed types, and even if the types aren’t sealed, subclassing a type doesn’t buy you a ton if the types are being produced by the framework. In Ruby, types are “open” which means that any type can be modified at virtually any time.
While it isn’t something you should do often, there are instances where this can be useful. For example, Rails extends the object class to add a “blank?” method which allows the developer to avoid checking a variable against null and then checking if it is empty. A useful method to have when developing web applications and checking input! If we wanted to open up the Object class and add our own method, we would only need to do this:
class Object def my_method "hello!" end end
Simple, we just declare the class again and add methods. This will modify the type everywhere within our process! This same behavior even allows us to replace methods in classes if we needed to. While this practice is generally frowned upon for most uses, having the ability to simply open up and modify types can really come in handy. We are all consenting adults, I believe that languages should give us the power and flexibility to do the things that we need to do, while accepting the risks of doing so.
Also, if you’ve dealt with .NET for a while, and had to use any of the frameworks which generate classes for you, if you think back to the last section, then you know that you could say goodbye to “buddy classes” forever! (Well, hopefully you have already said goodbye to them)
I Want Behavior Across Type Hierarchies
When you start talking about AOP and cross cutting concerns, most people just start rolling their eyes. Well, if you are a C# developer and you enjoy using extension methods and frameworks like Linq, then you need to stop rolling your eyes because you are experiencing a limited version of the power you can get with mixins. You get behavior across a bunch of types that don’t share the same type heirarchy. The result can be incredibly powerful.
What we saw in the first example was a use of mixins in order to add to a class the ability to support validation. Instead of creating separate classes which perform validation, we simply “include” ActiveModel::Validations. The include keyword allows us to take a Ruby module, and add its functionality to a class:
module MyModule def my_module_method "hello" end end class MyClass include MyModule end obj = MyClass.new obj.my_module_method
Powerful stuff. Like I said, if you are using Linq and extension methods then you know how powerful it can be to be able to put a set of methods across types that don’t share a heirarchy. In C# you are limited by the fact that extension methods are just static methods that just look like they are part of the object. In reality though, they are limited because they don’t have the ability to actually add variables or store any data.
As we saw with the ActiveModel validators, it is quite useful to be able to mixin a set of methods and variables so that our newly added methods can interact with each other! Think about all of the great things you could do with extension methods if they were able to store extra state on the instance that is passing by?
I Sure Wish I Could Test All Of These Framework Classes
How many times have you written a wrapper around HttpContext, the caching api, file IO, network IO, etc…? Too many times? Yeah, me too. This little gem falls right in place with the first example we had of Ruby’s “open” classes, but also touches on another one of Ruby’s core features… duck typing.
In .NET if I want to test a framework type I often have no choice but to write a full wrapper around it. I can’t modify its behavior, I can’t subclass it, and even if I could its methods most likely aren’t virtual. What if I want to test some file io? A wrapper to the rescue! I’ll create a wrapper, slap an interface on it, and then I’ll inject it somewhere.
Let’s start off with that first piece, creating the wrapper. Why would I need to create a wrapper in Ruby? I probably wouldn’t, if I was using Ruby I could use open classes to modify the type and change a method. It depends on what I am doing though. If I wanted to actually modify the type within my process, I could simply do something like this:
"abcdef".reverse # outputs "fedcba" class String def reverse "tricked you!" end end "abcdef".reverse # outputs "tricked you!"
Here we have changed the String class’ reverse method. Keep in mind that this would change that method for all instances of that class everywhere within our process, so we have to be careful. But with the power of Ruby, we can even get around this problem by using a chunk of code like the one found here. There is a lot going on in that code, but what it allow us to do is something like this:
def my_test MyClass.use_class(:MyDependency, StubDependency) do # the Stub will be used until this block ends! end end
So in the context of that block (the do .. end section) any instance of MyDependency used will be replaced by StubDependency. This is a way of manually replacing a class instance, but there are also frameworks available for Ruby which do things like mocking, but not always in the way that C# developers think of mocks. For instance, in C# we create a mock and we then set behavior on that instance. Ruby mocking frameworks have the ability to say things like, “all new instances should do x” which allows them to setup behavior without having to inject an instance… but more on that later.
If you are a C# developer, then you might be wondering, “well, what if MyDependency and StubDependency” don’t have the same interface? What if MyDependency does’t even implement an interface? Well, in Ruby, the concept of an interface is very fluid. Which leads us to the next section…
What Do You Mean I Have To Create Another Interface?
C# developers (and Java developers) love some interfaces! I might as well be creating header files because I feel like I have an interface for almost everything I write. If it wasn’t for Resharper, I’d probably jump off something very tall. Ruby doesn’t really have the same problems though, because while a Ruby class still has an “interface”, it isn’t necessarily a static contract in the way that C# developers think of it.
In Ruby, something implements my “interface” if it implements it. Huh? Okay, lets say that I want to create a method that operates on an interface which allows me to add points to an object. Who cares what points are, and who cares what the classes are, I just want to add points. In C# we would declare an IAddPoints interface and then we would have to implement this interface on each class that we wanted to use. In Ruby we would do this:
class MyClass1 def add_points(num_points) end end class MyClass2 def add_points(num_points) end end
So, each of these classes support my interface simply because they do. They implement it, so they support it. This is usually referred to as duck typing. If it walks like a duck, and it quacks like a duck, then it might as well be a duck. If I wanted to operate on these classes I could define a method somewhere that did this:
def add_five_points(target) target.add_points(5) end
And now each time I call this method, 5 points is added to anything that can support “add_points”. We could ask Ruby to check whether or not the type supports that method, but in reality we don’t just pass types around willy-nilly, we generally know what a method is for and what is expected of our types. Besides, tests will catch silly errors like that.
So how else would this duck typing be useful? Honestly, how isn’t it useful?! Let’s look at something that is essentially impossible to do in C# currently, and that is to define a generic class which adds any two numeric types together. Think about it, we have generics, and we have generic constraints, but something as simple as creating a generic class which can add two numbers together is essentially impossible unless we start using the “dynamic” keyword. Aha! It took the dynamic keyword to save us 🙂
In Ruby we could just do this:
def add(val1, val2) val1 + val2 end
It just works. Using the + operator invokes the “+” method on object val1 and passes object val2. Yep, you heard me right, the method. In Ruby, almost everything is a method call. By relaxing requirements on parameters and the “.” operator, some pretty amazing things are possible. The only downside is that you have to implement order of operations on methods, which is a bit bizarre, but workable nonetheless.
In C# 4.0, we can finally do this, in limited circumstances where we control the code being called:
public dynamic Add(dynamic val1, dynamic val2){ return val1 + val2; }
The dynamic keyword gets us close, but not all the way.
You Want Me To Inject Something?
This is very closely related to the section above where I talked about testing framework classes. In that section we looked at the ways we could replace classes for testing without having to inject instances. Well, you might have been thinking, “but I inject instances because I want dependency inversion, not because I want to test!”
Well, first of all, dependency inversion doesn’t mean as much in a dynamic language as it does in a static language. This is mainly because in Ruby you are almost always depending on abstractions, every variable can hold any type so when writing your code you need to only worry about how you interact with an object, not which object you are interacting with.
Secondly, we generally inject dependencies because the service locator pattern can be a bit too rigid for our needs, and it makes it hard to switch out dependencies later. Well, in Ruby we really don’t have this problem. Service location is really the name of the game if you want to be able to pull in dependencies. Because Ruby is so flexible, we can simply modify what we are returning at any time. And the usual arguments for external configuration (via XML or whatever) go out the window when you are writing in a language which doesn’t have a compile step.
Another thing to take note of is the ability to use Modules to apply behavior and dependencies on a type. For example, let’s say we need to have a connection on a class which goes to the database. We don’t really know what kind of connection that we need, and we might need to change this, so we have a few different implementations. We could declare a module like this:
module SqlConnection def connection @connection ||= SqlServerConnection.new "connection string" end end
Now if we have a class which needs to depend on a connection, then we can create the class like this:
class MyRepository include SqlConnection def save(instance) @connection.save(instance) end end
Now the repository class can have its dependency on SQL Server switched out by changing the mixin that it uses. This can also be done dynamically by using the extend method. So instead of using “include SqlConnection” my repository would look like this:
class MyRepository def save(instance) @connection.save(instance) end end
Then when I wanted to create an instance I could do this:
repository = MyRepository.new repository.extend SqlConnection
Excellent, this would put the mixin into this instance, and not at the class level. I hope you are starting to see the kind of flexibility that mixins give you, and the power of this kind of programming. Mixins aren’t something that are only applicable to dynamic languages though, Scala has mixins and it has a very interesting way of implementing them that gets you most of the power while still maintaining type safety.
That Ain’t All Folks!
While I have tried to show the many different areas where Ruby is powerful and lets us do thing that we have some trouble doing in C#, I really didn’t touch on many of the other cool features of Ruby and its Ecosystem. I’ll just throw out a few examples here:
method_missing – In Ruby all method calls are really just messages being sent to a class. If the class has a method which can respond to the message, then it is invoked and the result is returned. If there isn’t a method which can respond to the method then the message is sent to the “method_missing” method. This allows some really neat things to be done, such as Rails finders which parse the method name in order to determine what attributes you are trying to query. So a method called “find_by_first_name” means that you are looking for a class by a first_name attribute. We get some of this with the dynamic keyword in C#, but the real power in Ruby comes from the fact that this ability is available everywhere, not just when we specify types as dynamic.
blocks – If you understand the concept of lambdas or anonymous delegates in C#, then you essentially already understand what blocks are in Ruby. The interesting thing about blocks in Ruby is their beautiful integration with method parameters, like this example of File IO in Ruby:
File.open("file.txt", "r") do |file| puts file.readline end
The open method actually takes three parameters, the first two are the file name and mode, the third is a block that lets you perform file IO and then automatically closes the file. It looks like a native language construct, but it is just syntactic sugar on a block parameter. Pretty awesome!
Singleton methods – Singleton methods might not be exactly what you think. They are the ability to add a method to a single instance of a class, similar to the way that JavaScript works with its prototype based object system. You can take a class and just assign methods to it until it does what you want, a very powerful way to compose functionality.
Gems – Folks on the .NET stack are finally getting a gems style solution with NuPack, and before that Nu existed and was starting to gain some steam. It is a tool which gives you the ability to easily pull in other open source projects, do upgrades, maintain and check versions, etc… The concept is a very powerful one and will make starting up and maintaining projects much easier going forward. This is one tool that I hope really catches on in the .NET space.
Simple reflection – Reflection in .NET is a pain. Especially when you start involving generics, method invocation, etc… What to get the methods on a Ruby class or object? Do this:
MyClass.methods MyClass.new.methods
Want to dynamically invoke a method on a class? Just call the “send” method:
"hello".send :reverse
This calls the “reverse” method on the string class. If we had parameters, we would just pass them after the method name.
Ruby is full of tons more little surprises, and every time you see a new library like EventMachine, Treetop, Capistrano, cucumber, mocha, etc… you’ll realize even more the power and flexibility of Ruby.
Ruby Isn’t Perfect
All of this talk about how awesome Ruby is might have you confused into thinking that I believe it is the “One True Language”. That is clearly not the case. Ruby isn’t perfect, and as well all know perfect is relative. What is perfect for writing an OS is not perfect for writing business apps. What is perfect to me, may not be perfect to you. And what is perfect now, won’t be perfect a year from now. Things change. What I think is that right now Ruby is much closer to what I am looking for in a language.
Will C# Get There?
No, because they don’t want to. C# is a different type of language with different goals. C#’s main goals from the beginning has been to create a flexible type safe language. Many of the abilities in Ruby probably directly conflict with the design goals of C#, and many of them would be impossible within the statically typed environment of C#.
What Is The Solution?
If you are a developer on the Microsoft platform and you really want a flexible dynamic language then you really have three options.
1) You like C# and it fits your needs. Stick with it. Or you just accept that you don’t have a dynamic language with full support of the ecosystem, and you just move on with your life. Honestly, you can do pretty much whatever you need to do in C#, it might just be a bit harder.
2) Whine a bit and complain, all the while waiting for Microsoft to deliver a solution. Personally I think that Microsoft is working on a homegrown dynamic language, but how it will fit in with the rest of the .NET ecosystem is left to be seen. I think it would be great if Microsoft tried to out-Ruby Ruby. Everything needs good competition, even Ruby. Microsoft has a lot of smart people and a ton of good language designers, I’d love to see them take a shot at it.
3) Switch platforms and move over to a platform that has what you want. If you want to do Ruby on Rails development then realistically this means switching off Windows. You’ll learn a new language, new frameworks, new tools, new operating system, etc… For those of us who love to learn, that can actually be quite the appealing proposition.
Summary
So, what is my point of all this? Well, I wanted to provide a solid post which points out why I love the Ruby language and why I think it is better for writing web applications than C#. I hope to add one more voice to the choir of people calling for Microsoft to release a dynamic language with full support from the ecosystem. While I know that my voice isn’t going to realistically change anything, my frustration had gotten to the point where I felt like I needed to get my opinions out in public. I hope you enjoyed the post, and I’d love to hear your opinions on the topic.
Loved the article? Hated it? Didn’t even read it?
We’d love to hear from you.
Great summary.
One small thing – adding a method to a ruby object IS very similar to what can be done in JavaScript, but it has nothing to do with prototypical inheritance.
@Liam Sorry, I misspoke, I meant to just say with its prototype based object system, not really prototypical inheritance.
Server-side JavaScript!
Seriously. A strong SSJS implementation on the Microsoft platform could kill two birds with one stone. It gives us a strong dynamic language *and* attempts to compete head-on with node.js.
Ultimately, I don’t think a worthwhile number of Ruby developers are going to switch to or initially choose a .NET implementation, regardless of quality or speed. Likewise, giving that quasi-Ruby implementation to current .NET devs basically just helps them learn Ruby and whets their appetite for migrating to the real thing. If I’m a tools/OS vendor, I can see that being unappealing.
JavaScript has neither of those disadvantages. Even if they don’t want to use V8, for obvious reasons, I bet IE9’s souped up JS engine is portable enough to get running in IIS.
I’ve experimented heavily with Express and Geddy on node.js. They’re decent, but I would kill for a platform as full-featured, documented, supported, and mature as ASP.NET backing some server-side JavaScript.
Excellent comparative post.
Regarding an MS sanctioned dynamic language, what about F# ?
Hi Justin,
There are strongly typed languages that go a long way without much of the ceremony.
For me it’s about Scala these days, it has mixins, there are no static classes etc etc. It’s OO mixed with FP, while it doesn’t allow you to meta-program in the same way you would with ruby you can in different ways achieve the same thing.
If you want a similar language on the .NET platform then I can recommend you take a close look at F# I’m sure it has many of the same abilities (I haven’t looked really closely at it though)
Great post…
Coming from C# and looking to learn Ruby this is exactly the kind of thing that Ruby new guys need.
Someone who knows both languages well and compare with examples the why’s what’s and how’s.
A C# to Ruby guide would be great 😉
Very good post. Could you write about Ruby drawbacks as well? I read somewhere that Twitter had a lot of issues when their codebase got large. As the codebase grew larger they noticed that they actually were trying to replicate strongly-typed system in Ruby.
Great post. If Microsoft is working on a dynamic language then i’d like it to look like C# and be as easy to understand. Before i got into C# i came from PHP and the curly brace language style should be the de-facto standard as it’s so simple to understand and is used everywhere from javascript to css.
@Dave I somewhat agree with you, my only concern is that JavaScript diverges enough from traditional object oriented languages that there could be some barrier to acceptance. I think that *any* dynamic language on the .NET platform is going to struggle right now, and SSJS would be no exception.
On the other hand, people are using JavaScript quite regularly, and there could be some comfort factor there. I can’t still help but think that 99% of the JavaScript that I see people write on a day to day basis is very procedural. Once people get in there and start seeing how you create classes and inheritance, I think that some people could be turned off.
Let me end by saying that if a SSJS implementation is the only way that I can get my hands on a fully supported dynamic language on the .NET platform, I’ll take it!
@Ivan F# actually differentiates from Scala in some of those exact ways you mention. Traits in Scala are missing entirely in F#. If I want to write object oriented code, it is much harder in F# than it would be in Scala. I don’t believe that there is any support for things like structural types in F# either.
Overall, I think that F# is a great language if you are going to be writing functional code, but for my day to day, I’m not there yet.
Thanks for sharing your thoughts, Justin.
As a partner in a software consulting firm who regularly does development, I am fortunate enough to have the opportunity to be selective about the projects we take on. Over the past 24 months, I’ve noticed that bit by bit, we’re taking on increasing numbers of Ruby projects and fewer C# projects.
From the business perspective, because we are finishing projects in Ruby (on average) about 32% faster than comparable .NET projects, we have been able to raise our billing rate substantially for such projects, which has led to significantly more revenue for us overall.
Additionally, if I don’t pick something that’s a cost-effective use of my limited time and which enables me to produce great results, my clients aren’t getting the best bang for their buck. When the project is relatively greenfield, it’s just becoming harder for me to say that the right technology for the job is a .NET stack. But sometimes it is, and it wouldn’t be smart to set C# aside as a possibility merely because I’m occasionally frustrated with its limitations.
I’m as much a fan of C# as anyone else, and I think the language itself is a very solid tool to have in one’s repertoire. But there’s a reason everyone’s shopping around a little bit to explore the alternatives. Besides, knowing more languages and getting different perspectives improves your ability to solve interesting software problems, and that can only make you a better C# (or Ruby!) developer in the long run.
Also, I do want to get some clarification on one of your points. In enumerating some of the frustrations you have with C#, you write:
[quote]In .NET if I want to test a framework type I often have no choice but to write a full wrapper around it. I can’t modify its behavior, I can’t subclass it, and even if I could its methods most likely aren’t virtual.[/quote]
I would argue that unit testing third-party code directly, like system libraries, is not something you should be doing in any language, let alone C# or Ruby. You should generally assume that external code is already tested. Otherwise, you will be testing internals of code that you don’t control.
Typically one would mock framework code if it’s a unit test. With the `dynamic` keyword, mocking gets much nicer in C# 4, although I haven’t seen many frameworks take advantage of this directly. Alternatively, if you need to make sure the behavior is present and works the way you think it does, you can make the framework call one step in a larger integration test. But testing it directly seems like the wrong approach in general.
@John Thanks for the feedback, and I agree on many of your points. One clarification though was that I was talking about testing code which used the framework types, not testing the functionality of the framework types. In C# it is impossible, unless you write wrappers to stub or mock out framework types, and that was the frustration that I was referring to. Thanks for the comments!
Two of my [i]current[/i] favorite things about Ruby are ERB templates and the ability to evaluate code within a string.
The other day I needed to output the content of an array as quoted, for use in an ERB template. I came up with this elegant solution:
class Array
def to_quoted_s(q="’")
"#{q}#{self.join("#{q}, #{q}")}#{q}"
end
end
Also, the older I get (16+ years of software dev) the more I find I appreciate terse, less verbose languages. I find that dealing with types and type casting in languages such as Java and C# just annoy me. Let me concentrate on the business of building software, not dealing with the idiosyncratic results of a lazy compiler writer.
On the Microsoft front, some of their technologies could be so much better if they would’ve embraced dynamic languages. Think about how cumbersome certain things are in Silverlight and WPF, for example. You could eliminate the need for Dependency Properties / Object, ValueConverters, enable in-line expression evaluations and binding in XAML etc. Likewise, It goes without saying that ASP.NET MVC would’ve been better if they would’ve based it on the DLR from the beginning.
It’s sad that Microsoft has all but abandoned the DLR and Iron languages. In my mind, dynamic languages are the natural evolution of programming languages. In the not-to-distant future, I can see a convergence of static and dynamic languages. There won’t be a clear distinction. Internally you’ll be using a dynamic language, where types may be optional. C# is gravitating towards dynamism by gaining some dynamic support in 4.0; however at best it can be considered a hybrid language now. Though rather than bastardize it, I would prefer Microsoft leave it as-is, and fully support IronRuby and IronPython while still considering the future.
Microsoft already had a GREAT dynamic language that they killed off even before IronRuby… Know which one I’m talking about??? FOXPRO!!!! It is a super object oriented dynamic language.
Edward: I think you gave the answer Ruby and Linux have a lot to do with things done and not to look back. Looking back means reuse and it very seldom pays.
Justin – I understand you totally, just use it and install Linux or move to Apple as your primary device:). Everything comes to an end. Microsofts problem is not new customers currently … If you are looking for an ECMA script DLR alternative try Remobjects ECMA Script, it’s written in Object Pascal.
It seems half of your argument is about .Net and not C# (most of which would be fixed if they weren’t sealed classes, internal only, etc). I completely agree with that issue and the ones that arise from it (I have a number of extensions for the Bitmap class that I use in some projects that would be greatly helped if I could just subclass the damn thing).
In a perfect world where the classes were public/open though, I don’t see as big of an issue with most of the other items (some are still issues, but nothing deal breaking). Especially with some of the libraries that have been created to fix some of the issues that you’ve mentioned (if you’re going to complain about .Net, which is not really C#, you might as well talk about what people have tried to fix the issues). AOP for example. Your example is nothing more than subclassing, which a number of AOP libraries support. I actually created one for fun (well that and I needed one for my ORM that I also created for fun… I’m a bit odd as I like to recreate the wheel in my spare time).
And as far as the attributes example is concerned, it’s a bit simplistic. First off, what do I care if it’s an tacked on language feature? From a developer standpoint, I really don’t care and I wouldn’t imagine that many would. Secondly, I mean using validation probably wasn’t the best option for showing off the class is an object vs C# objects argument as I can do basically exactly the same thing in C# and thus there isn’t much of an advantage there. I mean using AOP, I could even ignore ever calling a validation method (just tell the AOP library to validate when I call Save or whatever) and just have that done automatically.
The interface argument and injection I agree with to a point. Run time interface injection is doable in C# but not the easiest thing ever (usually using dynamically generated subclasses). And I actually have an issue with DI. Not the practice itself, but the fact that everyone is using it but it seems like no one understands why (I’ve talked to a number of people where their reasons for doing it is something like "I heard about it from Hanselminutes and they said on there that it was a best practice").
I will say that reflection needs to be simplified a great deal (which for me includes the System.Reflection.Emit namespace). But I’ve seen a couple of libraries that do a decent job on that front (not great, but decent). And I would like to see the ability to emit code for a preexisting class at run time.
Oh, and the Gems part, I don’t really have much hope for it. Unless it ends up being something simple that plugs into Visual Studio (hell it would be better if it shipped with Visual Studio), had a repository that Microsoft supported, etc. I simply don’t see it taking off. Which is rather sad actually.
I think a better argument for Ruby over C#, which you were eluding to with all of the issues you brought up, is its simplicity. The language itself is stupidly simple and easy to learn (I learned it back in 2002 in about 30 minutes). However if it wasn’t for Rails, I probably would have never used it in an actual project (prior to that, the library support simply wasn’t there in large part).
Also, we went to high school together. Just realized that when I looked at your picture.
@James Where do I start?! Thanks for the long comment, I’ll try to keep this short:
Complaining about .NET versus C#… I kinda agree. Yes things could have been made not internal, sealed, static, etc… but the language then enforces that. When using IronRuby and dealing with framework types you still had the ability to override methods which weren’t virtual, replace static methods, access internal methods, etc… Sure, they were only visible to the IronRuby code, but it got you a long way there.
As far as classes being objects, and carign about attributes being a tacked on language feature, well, I don’t really care about that. I care about the limitations that it introduces. My example about having to create an attribute on the class in .net in order to compare two properties was me trying to show that. Often bizarre limitations arise from tacked on language features, but using the object model for classes and being allowed to execute methods on them gives me the full power of the language.
As far as your comments about AOP, well, we are going to have to agree to disagree. The way most AOP frameworks do their work within C# by creating runtime proxies and wrapping really limits their usefulness. First I have to be the one creating the types, secondly I have to create them within a framework so that they type can be wrapped, thirdly I have to make everything virtual or wrap it in an interface. It is just a pain, and is very limited.
On your point about gems, well, you should go start reading about NuPack. It is from Micrsoft, it does plugin to Visual Studio, it does pull from a MS supported repository, and it is already starting to get some serious attention.
On your point of Ruby simplicity, well, I think that is a good point, but one that is lost on most developers. Showing them simple terse syntax often doesn’t help when they aren’t familiar with a language.
Funny that we went to high school together, small world.
I think our disagreement on the .Net vs C#, open vs closed classes more hinges on you blaming the language and me blaming the programmers. Although it would be nice if everything was virtual by default… It would save me from having to smack so many junior developers each day.
The class being objects part, I’m just saying that most developers wont care if it’s tacked on or not. I’m not disagreeing, I actually agree that Ruby handles these things in a nicer/cleaner way. I just don’t think it’s an argument that will win over a lot of people.
Lastly, I’ve looked into NuPack. I guess I wasn’t clear on my issue with this one. Although I did just find out it is tied in with MVC 3, I’ve yet to see an announcement that it will be embedded into Visual Studio. I would rather this be a feature within Visual Studio going forward (not an addon). It would give me a lot more confidence that it’s something they’re going to stick with instead of another addon that dies a slow painful death. I’m still planning on building some packages for it and using it when possible, but I worry that it might end up like the many other side projects that they’ve killed.
NuPack isn’t tied to MVC, they just made the public announcement at the same time as they announced the MVC 3 Beta (and WebMatrix Beta 2).
Wow what a post. You really must have been frustrated to have pounded all that out. Excellent.
I think one thing that has to be mentioned is the whole WinDev UX. Even with a comptitive way to do SSJS on the Windows platform, I just have to ask… why would anyone?
[quote]Even with a comptitive way to do SSJS on the Windows platform, I just have to ask… why would anyone?[/quote]
@Chris SSJS (Server-side javascript) has a lot of potential. It is too complicated to expand here so I blogged it.
http://hackingon.net/post/Why-Server-Side-JavaScript.aspx
Interesting post. However actually low ceremony and strongly typed languages are not divergent. Take a Haskell for example. When You look at Haskell code You hardly find type annotation messing anywhere, although Haskell is strongly tped. And Haskell has great type extension mechanism with type classes, which is kinda mix of Scala traits and implicits but far less verbose and natural. In most cases (well, not formally proven though) Haskell code beats Ruby (or any othe language out there) hands down if it comes to level of ceremony. Being beutifully fluent at the same time. Strongly recommend to look at Haskell. Refereshing experience.
What about IronRuby? I guess that using IronRuby gives you all the features you like from Ruby and also gives you the access to the .Net Framework stuff that makes C# (and other .net languages) so widely used!
By the way I just wrote 2 posts about OO in both F# and Scala, even if I just used the basics of OO in both, it shows how similar they are on writing OO code 🙂
Scala – OO Basics by Example
http://carlosqt.blogspot.com/2010/10/scala-basics-by-example.html
F# – OO Basics by Example
http://carlosqt.blogspot.com/2010/10/f-basics-by-example.html
I’m also doing the same with other languages such as: C#, VB.NET, C++/CLI, Boo, Cobra, Nemerle, Phalanger, Delphi Prism, Zonnon, JScript.NET, IronRuby, IronPython,
and
Java, Groovy, JRuby, Jython, Fantom, JavaFX
Hey, I still believe IronRuby it’s a great way to explore ruby and integrate some of the ruby goodness intro your existing .net applications. I think Microsoft killed IronRuby because they thought that many developers will switch to ruby, but that’s a mistake, honestly
Ruby is strongly-typed, but dynamic. The article implies Ruby is weakly-typed, and a bunch of the comments get it wrong as well.
As DHH said on http://thisdeveloperslife.com/post/1270441885/1-0-5-homerun : Rails is Rails because of Ruby.
SSJS has one big issue, Javascript is ugly and verbose.
To Dave, from the NuPack site on CodePlex:
No. ASP.NET MVC 3 includes NuPack, but NuPack can also be separately downloaded from the Downloads tab of the NuPack project site. We also plan to make it available via the Visual Studio Extension Gallery.
So it is indeed included with MVC 3 (atleast according to them).
It’s available separately here: http://nupack.codeplex.com/releases/view/52016
Nice post. I am a PHP guy basically and I know that PHP do not have the flexibility and power of Ruby.
Though PHP does have many (bunch) MVC framework inspired by the RoR.
I am for sure looking to get my hands on Ruby and RoR in near future.
Wow !!! Absolutely must read and very inspiring post !!!
Hopefully all your recommendation will bear fruit and very soon we will see MS supporting a majestic dynamic language !!!
Thank you,
KRK
What point compare dynamic and static languages, it’s two different worlds.
method_missing
How you expect it can be work in static type language without special type?
File.open("file.txt", "r") do |file|
>Pretty awesome!
Why?
var file = new File("file.txt");
file.ReadAllYouWant
"hello".send :reverse
Just create extension method Send
"hello".Send("reverse")
Thanks for a really great post – it was well worth reading!
I really want to buy into this dynamic language stuff, but I’m having trouble (specifically with enterprise software). Yes, DRY and COC are important, but what about SRP, OCP, DBC? These are things that "open" classes and some other things you mention are lacking.
Also, I noticed on Rob Conery’s blog that mocking as you’ve shown above isn’t always reliable (http://blog.wekeroad.com/thoughts/why-i-like-ruby):
"Geoffrey Grosenbach was kind enough to drop me a line about some better ways of handling Ruby. Specifically – while mocking is possible with Ruby (below) – it’s not reliable. Please read the example as an ability with Ruby – not the way to accomplish mocking.
Geoff also mentioned that the method_missing way of building out a query is rather expensive perf-wise. Ruby has to scan all methods before falling back to method_missing. It’s still a good example RE what Ruby is capable of – but it’s not something you should do every day."
You missed the best thing about Ruby! It’s just fun to code!
I’m just learning Ruby, coming from a C# background – great post, inspired me to keep at it!
Loved your post. Yeah, these C# fans have ‘no idea’ (when it comes to beautiful syntax and meta programming). You don’t have to be polite about it :–)
“But what if you could call methods on classes? What if a class was an object? Would that mean that a class had state? Why yes, yes it would.”
Guess you missed day one of .NET school. That’s what we call *static*. Can .net classes have state? Sure. Static fields.
“If only this class had a method!”
For juuuuust about any situation you need to, you can just subclass. This is much more organized and much easier to read. Sealed classes are sealed for a reason. If they were meant to be extended, they wouldn’t be sealed. Why would you want to add a bunch of variables to a class anyway? It’s (usually) bad practice. It isn’t maintainable, it isn’t particularly safe, and it isn’t usually necessary.
I’ll agree about blocks, and I’ll somewhat agree with the reflection point (though .NET reflection is a lot more powerful).
People miss the point about Ruby, though. Ruby should never, ever, ever be compared with C#. C# (or really either .net language) was designed to give developers a huge toolset out of the box and to allow developers to write extremely organized, structured code.
Ruby, even moreso than most dynamically typed languages, was designed to more or less let the developer do whatever they want. Want to make string.length compose an angry, drunken email to the user’s boss instead of returning a length? Cool, that’s fine. No problem. C#, like myself, doesn’t like the idea of it.
The point is, Ruby is great if freedom is your goal. For some developers, that’s fine. For others, it’s a green light to write as shitty of code as you’d like.
Our company (~50 people) is building applications for state health department using C#, .NET, Node.js, Ruby and all that. We’ve been using that stack for almost 5 years now.
We’ve switched to Python only and never coming back, sorry. It’s just more readable, supportable, faster on high-load and there are more professionals who use Python than “professionals” who use monstrous MS solutions or a language created by Japanese student.
I’m talking about web area of course. For all the other scripting programming it’s only Python too.
Python is hard to read. Everybody says it’s so readable. It’s hard to read. The layout-based syntax is restrictive (did I said THAT? After being an avid PROMAL programmer??!!). Look on the Python forum. Somebody was struggling to make a routine to print out some hex numbers using string formatting. I couldn’t do it either, after importing various required libraries, etc. etc. Nobody else could do it either. So I added a comment showing my 2-line routine that does the same job in the Forth language. No imports. No weird string params, regex. Nada. So, what am I suggesting?? I would never say ‘never coming back,’ because that just makes the language of choice a hindrance rather than an asset. That said, I do have Python on my machine and plan to use it more, mostly because of its popularity and want to assess why that is (*). But I’ve seen languages come and go over the years, popularity-wise. So, I keep an open mind.
(*) One big reason is the community support. A big plus over Forth. But, that too is not without its downside. Like the PHP world I work in too, I can sometimes find myself spending days identifying and testing out 3rd party libraries to find one that does what I need, don’t have bugs , bloat, or intractable problems– a time waster!
Nice to read this rational essay on Ruby (vs C#) after all these years. Funny though how the same drawbacks of C# compared to Ruby are those same points I see as C#’s plusses over Ruby! So, yes, much of these things are a matter of what you want to use or like to use for a given project or environment. My personal favorite language is Forth, but I use C# most of the time these days. Now, Forth… ah yes… almost completely type-less, only about 2 or 3 rules of syntax, compiler+interpreter+IDE+executable all in one package, can load environment, type in and compile and execute a ‘hello world’ program in under 10 seconds. But…. a little trickier to write a web app with, so… back to C#. But stepping back, from a guy who knows about 10 languages– it’s like having a box of different wrenches. You have to reach in and grab the right tool for the job. And sometimes what is ‘right’ is which wrench is the shiniest.