Recently i was talking to Michael Silver about declarative vs. imperative programming; he found an article on the topic saying that declarative programming is overrated and that "languages like Ruby" allow writing imperative code that "looks" and "feels" declarative. The article didn't give any examples, but Michael sent me an example using ActiveRecord to define a database schema.
1: ActiveRecord::Schema.define(:version => 2) do
2:
3: create_table "comments", :force => true do |t|
4: t.column "body", :text
5: t.column "post_id", :integer
6: end
7:
8: create_table "posts", :force => true do |t|
9: t.column "title", :string
10: t.column "body", :text
11: t.column "created_at", :datetime
12: t.column "author_name", :string
13: t.column "comments_count", :integer, :default => 0
14: end
15:
16: end
After a while of figuring out the semantics of the Ruby syntax, i realized that it isn't even a *language* feature that the article was touting - it's simply a "fluent API" which is apparently fairly common in Ruby libraries.
So I thought I would try to create a library in .Net that would "feel" very similar to the Ruby style.
So, here's the same code in VB.Net...
1: With ActiveRecord.DefineSchema().AsVersion(2)
2:
3: With .WithTable("comments").UseForce()
4: .WithColumn("body").AsType(Of String)()
5: .WithColumn("post_id").AsType(Of Integer)()
6: End With
7:
8: With .WithTable("posts").UseForce()
9: .WithColumn("title").AsType(Of String)()
10: .WithColumn("body").AsType(Of String)()
11: .WithColumn("Created_at").AsType(Of Date)()
12: .WithColumn("author_name").AsType(Of String)()
13: .WithColumn("comments_count").AsType(Of Integer).UseDefault(0)
14: End With
15:
16: End With
...and here's the same code in C#...
1: ActiveRecord.DefineSchema(delegate(ARSchema s)
2: {
3:
4: s.WithTable("comments", delegate(ARTable t)
5: {
6: t.WithColumn("body").AsType<string>();
7: t.WithColumn("post_id").AsType<int>();
8: }).UseForce();
9:
10: s.WithTable("posts").UseForce(delegate(ARTable t)
11: {
12: t.WithColumn("title").AsType<string>();
13: t.WithColumn("body").AsType<string>();
14: t.WithColumn("Created_at").AsType<DateTime>();
15: t.WithColumn("author_name").AsType<string>();
16: t.WithColumn("comments_count").AsType<int>().UseDefault(0);
17: });
18:
19: }).AsVersion(2);
The VB and the C# versions both take advantage of the language features. VB supports the With statement, while C# supports anonymous delegates. Both of these scenarios were enabled with overloaded methods within the same library.