For the past few years I've heard a lot of hype about dynamic programming languages like Python and Ruby. The word on the street has been that their dynamic nature makes developers more productive that those of us shackled to statically typed languages like C# and Java. A couple of weeks ago I decided to take the plunge and start learning Python after spending the past few years doing the majority of my software development in C#. I learned that it was indeed true that you could get things the same stuff done in far less lines of Python than you could in C#. Since it is a general truism in the software industry that the number of bugs per thousand lines of code is constant irrespective of programming language, the more you can get done in fewer lines of code, the less defects you will have in your software.

Shortly after I started using Python regularly as part of the prototyping process for developing new features for RSS Bandit, I started trying out C# 3.0.  I quickly learned that a lot of the features I'd considered as language bloat a couple of months ago actually made a lot of sense if you're familiar with the advantages of dynamic and functional programming approaches to the tasks of software development. In addition, C# 3.0 actually fixed one of the problems I'd encountered in my previous experience with a dynamic programming language while in college.

Why I Disliked Dynamism: Squeak Smalltalk

Back in my college days I took one of Mark Guzdial's classes which involved a group programming project using Squeak Smalltalk. At the time, I got the impression that Squeak was composed of a bunch of poorly documented libraries cobbled together from the top graded submissions to assignments from Mark's class. What was particularly frustrating about the lack of documentation was that even looking at method prototypes gave no insight into how to call a particular library. For example, here's an example of a SalariedEmployee class taken from an IBM SmallTalk tutorial

"A subclass of Employee that adds protocol needed for 
          employees with salaries"

       Employee subclass: #SalariedEmployee
          instanceVariableNames:  'position salary'
          classVariableNames: ' '
          poolDictionaries: ' ' !

       ! SalariedEmployee publicMethods !

          position: aString 
             position := aString !
          position 
             ^position !
          salary: n 
             salary := n !
          salary 
             ^salary ! !

In the example above, there is a method called salary() that takes a parameter n whose type we don't know. n could be a string, an integer or a floating point number. If you are using the SalariedEmployee class in your code and want to set the employee's salary, the only way to find out what to pass in is to grep through the code and find out how the method is being used by others. You can imagine how frustrating it gets when every time you want to perform a basic task like perform a Web request you have to grep around trying to figure out if the url parameter you pass to the Http classes is a string, a Uri class or some oter random thing you haven't encountered yet.

For a long time, this was my only experience with a dynamic programming language and I thought it sucked...a lot.

Why I Grew to Love Dynamism: XML and C#

The first half of my career at Microsoft was spent working on the XML team which was responsible for the core XML processing APIs that are utilized by the majority of Microsoft's product line. One of the things that was so cool about XML was that it enabled data formats to be as strongly structured or semi-structured depending on the needs of the application. This flexibility is what gives us data formats like the Atom syndication format which although rigidly structured in parts (e.g. atom:entry elements MUST contain exactly one atom:id element, etc)  also supports semi-structured data (e.g. atom:content can contain blocks of XHTML) and enables distributed extensibility where anyone on the Web is free to extend the data format as long as they place their extensions in the right namespace.

However one problem we repeatedly bumped against is that data formats that can have unknown data types show up in them at runtime bump up against the notion of static typing that is a key aspect of languages in C#. I've written about this in the past in posts such as What's Right and Wrong with Code Generation in Web Services which is excerpted below

Another problem is that the inflexible and rigid requirements of static typing systems runs counter to the distributed and flexible nature of the Web. I posted a practical example a few years ago in my post entitled Why You Should Avoid Using Enumerated Types in XML Web Services. In that example, I pointed out that if you have a SOAP Web Service  that returns an enumeration with the possible value {CDF, RSS10, RSS20} and in a future release modify that enumeration by adding a new syndication format {CDF, RSS10, RSS20, Atom} then even if you never return that syndication format to old clients written in .NET, these clients will still have to be recompiled because of the introduction of a new enumeration value. I find it pretty ridiculous that till today I have list of "people we need to call and tell to recompile their code whenever we change an enum value in any of our SOAP Web Services".

I came to the realization that some degree of dynamism is desirable especially when dealing with the loosely coupled world of distributed programming on the Web. I eventually decided to ignore my earlier misgivings and start exploring dynamic programming languages. I chose IronPython because I could focus on learning the language while relying on the familiar .NET Framework class library when I wanted to deal with necessary tasks like file I/O or Web requests.

After getting up to speed with Python and then comparing it to C# 2.0, it was clear that the dynamic features of Python made my life as a programmer a lot easier. However something interesting happened along the way. Microsoft shipped C# 3.0 around the same time I started delving into Python. As I started investigating C# 3.0, I discovered that almost all the features I'd fallen in love with in Python which made my life as a developer easier had been integrated into C#. In addition, there was also a feature which is considered to be a killer feature of the Ruby programming language which also made it into C# 3.0.

Python vs. C# 3.0: Lambda Expressions

According to the Wikipedia entry on Dynamic Programming Languages

There are several mechanisms closely associated with the concept of dynamic programming. None are essential to the classification of a language as dynamic, but most can be found in a wide variety of such languages.
...
Higher-order functions
However, Erik Meijer and Peter Drayton caution that any language capable of loading executable code at runtime is capable of eval in some respect, even when that code is in the form of dynamically linked shared libraries of machine code. They suggest that higher-order functions are the true measure of dynamic programming, and some languages "use eval as a poor man's substitute for higher-order functions."[1]

The capability of a programming language to treat functions as first class objects that can be the input(s) or the output(s) of a function call is a key feature of many of today's popular "dynamic" programming languages. Additionally, creating a short hand syntax where anonymous blocks of code can be treated as function objects is now commonly known as "lambda expressions". Although C# has had functions as first class objects since version 1.0 with delegates and introduced anonymous delegates in C# 2.0, it is in C# 3.0 where the short hand syntax of lambda expressions has found its way into the language. Below are source code excerpts showing the difference between the the lambda expression functionality in C# and IronPython 

C# Code

//decide what filter function to use depending on mode 
Func<RssItem, bool> filterFunc = null;
if(mode == MemeMode.PopularInPastWeek) 
   filterFunc = x => (DateTime.Now - x.Date < one_week) ;
else 
   filterFunc = x => x.Read == false;

IronPython Code

#decide what filter function to use depending on mode
filterFunc = mode and (lambda x : (DateTime.Now - x.date) < one_week) or (lambda x : x.read == 0)

Although the functionality is the same, it takes a few more lines of code to express the same idea in C# 3.0 than in Python. The main reason for this is due to the strong and static typing requirements in C#. Ideally developers should be able to write code like 

Func<RssItem, bool> filterFunc = (mode == MemeMode.PopularInPastWeek ? x => (DateTime.Now - x.Date < one_week) : x => x.read == false);

However this doesn’t work because the compiler cannot determine whether each of the lambda expressions that can be returned by the conditional expression are of the same type. Despite the limitations due to the static and strong typing requirements of C#, the lambda expression feature in C# 3.0 is extremely powerful.

You don’t have to take my word for it. Read Joel Spolsky’s Can Your Programming Language Do This? and Peter Norvig’s Design Patterns in Dynamic Programming.  Peter Norvig’s presentation makes a persuasive argument that a number of the Gang of Four’s Design Patterns either require a lot less code or are simply unneeded in a dynamic programming language that supports higher order functions. For example, he argues that the Strategy pattern does not need separate classes for each algorithm in a dynamic language and that closures eliminate the need for Iterator classes. Read the entire presentation, it is interesting and quite illuminating.

Python vs. C# 3.0: List Comprehensions vs. Language Integrated Query

A common programming task is to iterate over a list of objects and either filter or transform the objects in the list thus creating a new list. Python has list comprehensions as a way of simplifying this common programming task. Below is an excerpt from An Introduction to Python by Guido van Rossum on list expressions   

List comprehensions provide a concise way to create lists without resorting to use of map(), filter() and/or lambda. The resulting list definition tends often to be clearer than lists built using those constructs. Each list comprehension consists of an expression followed by a for clause, then zero or more for or if clauses. The result will be a list resulting from evaluating the expression in the context of the for and if clauses which follow it.

Below is a code sample showing how list comprehensions can be used to first transform a list of objects (i.e. XML nodes) to another (i.e. RSS items) and then how the resulting list can be further filtered to those from a particular date. 

IronPython Code

 # for each item in feed        
 # convert each <item> to an RssItem object then apply filter to pick candidate items
  items = [ MakeRssItem(node) for node in doc.SelectNodes("//item")]
  filteredItems = [item for item in items if filterFunc(item)]

My friend Erik Meijer once observed that certain recurring programming patterns become more obvious as a programming language evolves, these patterns first become encapsulated by APIs and eventually become part of the programming language’s syntax. This is what happened in the case of the Python’s map() and filter() functions which eventually gave way to list comprehensions.

C# 3.0 does something similar but goes a step further. In C# 3.0, the language designers made the observation that performing SQL-like projection and selection is really the common operation and not just filtering/mapping of lists. This lead to Language Integrated Query (LINQ). Below is the same filtering operation on a list of XML nodes performed using C# 3.0

C# 3.0 Code

//for each item in feed        
// convert each <item> to an RssItem object then apply filter to pick candidate items
var items = from rssitem in 
              (from itemnode in doc.Descendants("item") select MakeRssItem(itemnode))
            where filterFunc(rssitem)
            select rssitem;

These are two fundamentally different approaches to tackling the same problem. Where LINQ really shines is when it is combined with custom data sources that have their own query languages such as with LINQ to SQL and LINQ to XML which map the query operations to SQL and XPath queries respectively.

Python vs. C# 3.0: Tuples and Dynamic Typing vs. Anonymous Types and Type Inferencing

As I’ve said before, tuples are my favorite Python feature. I’ve found tuples useful in situations where I have to temporarily associate two or three objects and don’t want to go through the hassle of creating a new class just to represent the temporary association between these types. I’d heard that a new feature in C# 3.0 called anonymous types which seemed like it would be just what I need to fix this pet peeve once and for all. The description of the feature is as follows

Anonymous types are a convenient language feature of C# and VB that enable developers to concisely define inline CLR types within code, without having to explicitly define a formal class declaration of the type.

I assumed this feature in combination with the var keyword would make it so I would no longer miss Python tuples when I worked with C#. However I was wrong. Let’s compare two equivalent blocks of code in C# and IronPython. Pay particular attention to the highlighed lines

IronPython Code

      for item in filteredItems:
            vote = (voteFunc(item), item, feedTitle)

            #add a vote for each of the URLs
            for url in item.outgoing_links.Keys:
                if all_links.get(url) == None:
                    all_links[url] = []
                all_links.get(url).append(vote)

    # tally the votes, only 1 vote counts per feed
    weighted_links = []
    for link, votes in all_links.items():
        site = {}
        for weight, item, feedTitle in votes:
            site[feedTitle] = min(site.get(feedTitle,1), weight)
        weighted_links.append((sum(site.values()), link))
    weighted_links.sort()
    weighted_links.reverse()

The key things to note about the above code block are (i) the variable named vote is a tuple of three values; the numeric weight given to a link received from a particular RSS item, an RSS item and the title of the feed Python and (ii) the items in the tuple can be unpacked into individual variables when looping over the contents of the tuple in a for loop.

Here’s the closest I could come in C# 3.0

C# 3.0 Code

// calculate vote for each outgoing url
 foreach (RssItem item in items) { 
       var vote = new Vote(){ Weight=voteFunc(item), Item=item, FeedTitle=feedTitle };
       //add a vote for each of the URLs
       foreach (var url in item.OutgoingLinks.Keys) {
           List<Vote> value = null;
           if (!all_links.TryGetValue(url, out value))
                value = all_links[url] = new List<Vote>(); 
                            
           value.Add(vote);                                                    
         }
   }// foreach (RssItem item in items)
//tally the votes
  List<RankedLink> weighted_links = new List<RankedLink>();
  foreach (var link_n_votes in all_links) {
       Dictionary<string, double> site = new Dictionary<string, double>();
       foreach (var vote in link_n_votes.Value) {
           double oldweight;
           site[vote.FeedTitle] = site.TryGetValue(vote.FeedTitle, out oldweight) ? 
                                  Math.Min(oldweight, vote.Weight): vote.Weight; 
        }
        weighted_links.Add(new RankedLink(){Score=site.Values.Sum(), Url=link_n_votes.Key});
    }
    weighted_links.Sort((x, y) => y.Score.CompareTo(x.Score));

The relevant line above is

var vote = new Vote() { Weight=voteFunc(item), Item=item, FeedTitle=feedTitle };

which I had INCORRECTLY assumed I would be able to write as

var vote = new { Weight=voteFunc(item), Item=item, FeedTitle=feedTitle };

In Python, dynamic typing is all about the developer knowing what types they are working with while the compiler is ignorant about the data types. However type inferencing in C# supports the opposite scenario, when the compiler knows the data types but the developer does not.  

The specific problem here is that if I place an anonymous type in a list, I have no way of knowing what the data type of the object I’m pulling out of the list will be. So I will either have to interact with them as instances of System.Object when popped from the list which makes them pretty useless or access their fields via reflection. Python doesn’t have this problem because I don’t need to know the type of an object to interact with it, I just need to know how what properties/fields and methods it supports.

At the end of the day, I realized that the var keyword is really only useful when constructing anonymous types as a result of LINQ expressions. In every other instance where it is acceptable to use var, you have to know the type of the object anyway so all you are doing is saving keystrokes by using it. Hmmmm.

Ruby vs. C# 3.0: Extension Methods

Extension methods is a fairly disconcerting feature that has been made popular by the Ruby programming language. The description of the feature is excerpted below

Extension methods allow developers to add new methods to the public contract of an existing CLR type, without having to sub-class it or recompile the original type.  Extension Methods help blend the flexibility of "duck typing" support popular within dynamic languages today with the performance and compile-time validation of strongly-typed languages.

I consider this feature to be the new incarnation of operator overloading. Operator overloading became widely reviled because it made code harder to read because you couldn’t just look at a code block and know what it does if you didn’t know how the operators had been implemented. Similarly, looking at an excerpt of C# code you may not realize that everything isn’t what it seems.

I spent several minutes being confused today because I couldn’t get the line

XAttribute read_node = itemnode.XPathEvaluate("//@*[local-name() = 'read']") as XAttribute;

to compile. It turns out that XPathEvaluate is an extension method and you need to import the System.Xml.XPath namespace into your project before the XPathEvaluate() method shows up as a method in the XElement class.

I’ve heard the arguments that Ruby makes it easier to express programmer intent and although I can see how XElement.XPathEvaluate(string) is a more readable choice than XPathQueryEngine.Evaluate(XElement, string) if you want to perform an XPath query on an XElement object, for now I think the readability issues it causes by hiding dependencies isn’t worth it. I wonder if any Ruby developers out there with a background in other dynamic languages that don’t have that feature (e.g. Python) care to offer a counter opinion based on their experience?

FINAL THOUGHTS

C# has added features that make it close to being on par with the expressiveness of functional and dynamic programming languages. The only thing missing is dynamic typing (not duck typing), which I’ve come to realize is has a lot more going for it than lots of folks in the strongly and statically typed world would care to admit. At first, I had expected that after getting up to speed with C# 3.0, I’d lose interest in Python but that is clearly not the case.

I love the REPL, I love the flexibility that comes from having natural support tuples in the language and I love the more compact syntax.  I guess I’ll be doing a lot more coding in Python in 2008.

Now Playing: Da Back Wudz - U Gonna Love Me


 

Wednesday, 02 January 2008 03:55:09 (GMT Standard Time, UTC+00:00)
While it's not as elegant as it could be, if you use an dictionary of IDictionary[string, object], you can cast back to the anonymous type just by knowing the order, name and type of the properties. The reason it works is that anon types are shared per assembly.

http://tomasp.net/blog/cannot-return-anonymous-type-from-method.aspx

It would work for your example; you could have your var vote = new { ... }, and later you could have an method like List[T] GetList[T](IDictionary[string, object] source, string key, T val)
{
object obj;
if(!source.TryGetValue(key, out obj))
{
obj = new List[T]();
source.Add(obj)
}

return (List[T])obj;
}

The list you get back will be strongly typed.

Oren Novotny
Wednesday, 02 January 2008 05:36:35 (GMT Standard Time, UTC+00:00)
Another thing I miss in C# is the ability to do things like:
(a, b, c) = (1, 2, 3)

I am really impressed with F# though. Makes the "functional" bits of C# and Python seem really weak, and although it is strongly-typed and not dynamic; it actually produces more readable code than Python due to type inference.
Wednesday, 02 January 2008 07:16:00 (GMT Standard Time, UTC+00:00)
At Amazon, I spent a lot of time with Scala (and no. Scala isn't an official language of Amazon - C++, Java, and Perl are it). It is very similar to F# on the .NET Platform. It is both functional and imperative. In recent releases (2.6.x), it supports a type of static duck typing. I have a simple example here - http://justinrudd.wordpress.com/2007/09/11/scala-260-supports-duck-typing/

But if you want a really thorough example, check out http://scala-blogs.org/2007/12/scala-statically-typed-dynamic-language.html. Ignore the first couple of paragraphs. The main author has being bashed quite a bit lately.

Supposedly they are going to spend some time getting Scala working well on the CLR this year. The JVM version is way ahead of the CLR one.

For most of my personal projects, I've moved off Ruby/Python onto Scala. It is a good, clean, static language with just enough dynamic language features to not kill the performance of my program. And given that it runs on Java 5 and up with no problems, I get access to a lot of libraries that just don't have an equivalent in Python/Ruby. Database interaction for example (JDBC while full of warts, is way nicer than each of the hodge podge libraries that Python/Ruby have).

I will admit that is kind of weird writing SWT code with Scala, but it works like a charm...
Wednesday, 02 January 2008 09:05:44 (GMT Standard Time, UTC+00:00)
On the lambda expression stuff, while there is no implicit conversion for those, you can of course make an explicit conversion and get very close to the syntax you would like: var filterFunc = (mode == MemeMode.PopularInPastWeek ? (Func&lt;RssItem, bool&gt;) (x =&gt; DateTime.Now - x.Date &lt; one_week) : (Func&lt;RssItem, bool&gt;) (x =&gt; x.read == false));
davidacoder
Wednesday, 02 January 2008 09:07:09 (GMT Standard Time, UTC+00:00)
Uh, can't paste code in here... When I didn't escape things, I got an ASP.NET error page saying that dangerous content was detected, now it looks like the above. Sorry, hope you can decipher what I meant.
davidacoder
Wednesday, 02 January 2008 09:24:20 (GMT Standard Time, UTC+00:00)
hmm the blog formular field is a little bit awkward
sorry to complain about it :(
she
Wednesday, 02 January 2008 09:42:18 (GMT Standard Time, UTC+00:00)
"Since it is a general truism in the software industry that the number of bugs per thousand lines of code is constant irrespective of programming language, the more you can get done in fewer lines of code, the less defects you will have in your software."

While this is generally true, it ignores the time required to FIX a bug, which is orders of magnitude shorter with static languages than with dynamic ones. It is also known that more than 70% project costs are spent in the maintenance phase - so even if you have, in a dynamic language half the bugs of equivalent static code, you will spend times more time, and thus money, on fixing them.

Some simple cases, like converting loosely typed input to string only output might justify using dynamic language, but as a rule you should shun them.
albert bulawa
Wednesday, 02 January 2008 10:07:53 (GMT Standard Time, UTC+00:00)
You should try Boo. It is like python but it runs on CLR and it is light years ahead of C#
onur gumus
Wednesday, 02 January 2008 12:13:01 (GMT Standard Time, UTC+00:00)
"While this is generally true, it ignores the time required to FIX a bug, which is orders of magnitude shorter with static languages than with dynamic ones"

Albert, can you point at evidence/data for this?
Wednesday, 02 January 2008 14:53:57 (GMT Standard Time, UTC+00:00)
The generic term for what you're describing with C# extension methods is 'monkey patching'. Python disallows monkey patching of core system types (like string), but you can monkey patch anything else. Ruby differs by not preventing you from patching core system types.

I like the analogy to C++ operator overloading. It's a remarkably powerful feature that you can exploit to do interesting things like generating mocks. You can also abuse it to do bizarre, unpredictable side-effecting operations as well.

In practice, if you look at large frameworks that use monkey patching extensively (Rails comes to mind) is that you don't generally run into conflicting monkey patches since you're not combining Rails in a single app with something else that does the same thing, like Merb.

Other dynamic languages have approaches to try to scope monkey patches (Smalltalk selector namespaces for example).
Wednesday, 02 January 2008 15:09:05 (GMT Standard Time, UTC+00:00)
A couple improvments to your python code. the all_links builder can be improved with the dict setdefault method:

for url in item.outgoing_links:
all_links.setdefault(url, []).append(vote)

(in 2.5 you can use a defaultdict, which does basically the same thing but is more performant)

and the sort/reverse can be done in one operation:

weighted_links.sort(reverse=True)

(Hitting submit again, I'm not sure if I failed the captcha or not...)
Wednesday, 02 January 2008 17:34:14 (GMT Standard Time, UTC+00:00)
I find it kind of funny (and sad at the same time) that the author of the following quote confuses "strongly typed" and "statically typed":

"[...] with the performance and compile-time validation of strongly-typed languages."

Python and Ruby are both strongly typed! But they are not statically typed, that's the difference.
Robin
Wednesday, 02 January 2008 18:06:59 (GMT Standard Time, UTC+00:00)
Robin,
I didn't write that line. The text above clearly states "the description is EXCERPTED below" and it is blockquoted which should imply I was copying it from somewhere else. :)
Wednesday, 02 January 2008 19:18:43 (GMT Standard Time, UTC+00:00)
Dare: I didn't say you wrote it, I said "the author of the following quote", which isn't you but the one you quoted. So, no offence to you intended.
Robin
Wednesday, 02 January 2008 19:21:27 (GMT Standard Time, UTC+00:00)
PS: The comment system is acting strangely, I had to submit multiple times and there was no indication as to whether the submit was successful or not.
Robin
Wednesday, 02 January 2008 20:02:13 (GMT Standard Time, UTC+00:00)
Your criticism of Smalltalk is unconvincing - the problems you had seem to have been related to poor documentation. A statically typed language forces you to name the type; a dynamically typed language can handle more variety (but requires more documentation).

And AFAICT, this particular point is no different in Python or Ruby.
Wednesday, 02 January 2008 20:16:25 (GMT Standard Time, UTC+00:00)
Stefan,
The argument against Smalltalk isn't meant to be convincing. It's an explanation of why I didn't like dynamic languages based on my experiences working on group projects in a college class over seven years ago.

Even then I'm glad you concede that dynamically typed languages need more documentation than statically typed ones (even if it simply to mention the expected type of input and return parameters).
Wednesday, 02 January 2008 20:27:25 (GMT Standard Time, UTC+00:00)
Fair enough.

I'll not though that Smalltalk is one of the few (the only?) mainstream languages that has a syntax that makes calls much clearer -- i.e. instead of "func(a, b, c)" you have something like "func 'a' index: 3 width: 5".
Wednesday, 02 January 2008 22:18:44 (GMT Standard Time, UTC+00:00)
Python is lame, Ruby is not. Wrong choice on your side.
grimen
Wednesday, 02 January 2008 22:31:23 (GMT Standard Time, UTC+00:00)
Actually CA (ne Nantucket) introduced the concept of blocks of code that could be passed around like data back in the early 90's (if my memory isn't too fuzzy) with their version 5.0 release of Clipper (an xBase clone.) They called them "Code Blocks" and explained them as "assignable unnamed functions...[that] can be stored to variables, passed as arguments, and so forth."
Thursday, 03 January 2008 03:18:16 (GMT Standard Time, UTC+00:00)
As far as Ruby's open classes are concerned, I'm honestly not quite sure how users of other OO languages live without that ability. There are certainly arguments against extending classes, but it sure is nice to have the option. If I create a method that is specific to a String class, do I really want to subclass String and explicitly create a MyString object every time instead of just assigning var = "foo"?? No, and personally, I despise calls such as (super contrived example -- let's assume toLower() is built-in, but there's no method to upcase the string) upperCase("FOO".toLower()); That's just fugly. What we really want is "FOO".toLower().upperCase(); and we can do that type of stuff in Ruby with open classes. Using Python or Java leaves me wanting open classes.
Thursday, 03 January 2008 06:21:17 (GMT Standard Time, UTC+00:00)
I'm a Ruby programmer as well, and I want to comment on the open classes and monkey patching.

One of the key areas in which monkey patching is necessary, is creating DSLs, a field in which Ruby is gaining widespread traction.

The ability to include stuff in already existing classes is a way to make sure that everything really _IS_ an object, without requiring the programmer to write excessive amounts of code.

For instance, in Java you write a MyApplication class with a public static void main(String[]) method. In Ruby you just write your program in an .rb file and run it. Now, what really happens is that your .rb file is seen as an extension to the basic Object class, so methods that seem as if they're in the 'global' scope are actually in the Object class by design.

This feature is easy to abuse. But I've never seen horrible cases of it, because the people who write frameworks generally have a very good idea of what they're doing.

I actually used monkey patching on Rails itself in a project we're doing, to inject custom code at a specific point in the Rails rendering process, making it do something the designers did not initially think was needed. This had been downright impossible without monkey patching, and in another language it would require me to create a custom version of the framework, hacked to my needs, which is a much much worse prospect than simply risking a bit of programmer confusion (which is a small risk, considering I'm documenting everything :P).

- Simon
Simon
Thursday, 03 January 2008 06:24:04 (GMT Standard Time, UTC+00:00)
It is unfortunate that people start language comparisons with the explicit intention of offending others. C# is a terrific language, it really is and I like the way it is evolving.

The keyword here is 'evolving'. You didn't like a particular small thing about Smalltalk, ok, I give you that. Sometimes instinct and taste play a large role and that's normal.

Just remember that Smalltalk refined and set most of the OO concepts that we now take for granted. Yes, I know history, Simula and Eiffel came before, but it was Smalltalk that solidified the foundation: VM, GC, OO, and everything that's consider a commodity nowadays.

As for Python and Ruby. C# now have some of their features. I wonder if C# 3.0 would be what it is today without having Python, Ruby and others to be inspired from. The same way Ruby benefited from Perl's previous experiences.

We don't need to think like Highlanders: "there can only be one". This is lame. Why not "we can always learn some more". Even Microsoft is not that single-minded. Otherwise why be inspired by OCaml to implement F#, or why hire smart guys like John Lam to lead IronRuby? I have to give them credit, and if you like C#, you should do the same.
Thursday, 03 January 2008 08:28:58 (GMT Standard Time, UTC+00:00)
Dare, I'm glad that you have enjoyed your time in Python. I believe I'm on record enough times that I believe dynamic languages will eventually replace static languages for the majority of the code we write - even on .NET. Along with dynamic typing, I really value dynamic dispatch in languages like Ruby and Python.

I just wanted to point out that C#'s Extension Methods != Ruby's Open Classes. With Ruby, you can add new methods and instance variables at runtime. With C#, you can make it look like you are calling static methods as if they actually belonged to the original class. But its just a compiler trick and those methods are limited in what they can do. So while C#'s Extension Methods have some of the form of Ruby's Open Classes, they don't allow for the same meta-programming power that Mike Wilson and Simon mention.
Thursday, 03 January 2008 14:01:24 (GMT Standard Time, UTC+00:00)
I find it very interesting that you dislike extension methods because it "hides" information, yet you like dynamic types, which DO THE EXACT SAME THING. I never bought the argument when applied to operator overloading. I strongly believe people that made that argument were basing it on "gut feelings" and "personal taste", not on concrete evidence. I never once ran into code using operator overloading that caused me even the slightest hesitation. The vast majority of the time, the operators were overloaded to behave as one would expect, because it's in our nature to not purposely obfuscate code. Even when a non-intuitive use occurred (a classic example is the shift operators being used for I/O streams in C++), the code wouldn't lead you to think something else would occur. It would leave you not having any clue, and you'd read the documentation and quickly understand the usage. I never lost a second of productivity due to operator overloading, and gained a whole lot of productivity from the availability of the functionality. The EXACT SAME THING can be said for extension methods. This is especially true, when in the next breath you sing the praises of dynamic types. That still baffles me.
Friday, 04 January 2008 03:46:34 (GMT Standard Time, UTC+00:00)
Based on the other Oren's link, you can create a helper method like this:
public List[T] ListOfType[T](T type)
{
return new List[T]();
}

that allows you to write code like this:
var vote = new { Weight=voteFunc(item), Item=item, FeedTitle=feedTitle };
var value = ListOfType(new { Weight=voteFunc(item), Item=item, FeedTitle=feedTitle });
value.Add(vote);
Friday, 04 January 2008 05:09:04 (GMT Standard Time, UTC+00:00)
Whoops, my example was unnecessarily complicated. You can actually use the helper method like this:

var value = ListOfType(vote);
value.Add(vote);

If you need to use the anonymous type somewhere else then you can "re-specify" it using the more verbose syntax of the original example.
Friday, 04 January 2008 05:26:47 (GMT Standard Time, UTC+00:00)
Extension methods make for another interesting solution:
public static List[T] ListOfType[T](this T type)
{
return new List[T]();
}
allows you to write:
var voteList = vote.ListOfType();
voteList.Add(vote);

Here's another interesting but far more limited option:
var voteArray = new [] {vote1, vote2, vote3, vote4};
Saturday, 05 January 2008 22:44:20 (GMT Standard Time, UTC+00:00)
Dare Obasanjo wrote
> The argument against Smalltalk isn't meant to be convincing. It's an explanation of why I didn't like dynamic languages based on my experiences working on group projects in a college class over seven years ago.

It seems that you came to a sweeping conclusion based on a poorly written example without bothering to investigate further.

You'd have known better simply by reading an old book like
http://www.iam.unibe.ch/~ducasse/FreeBooks/WithStyle/SmalltalkWithStyle.pdf


> Even then I'm glad you concede that dynamically typed languages need more documentation than statically typed ones (even if it simply to mention the expected type of input and return parameters).

iirc polish variable naming had nothing to do with dynamically type checked languages :-)

I think when people talk about documentation they generally mean comments rather than variable or method or class names.


> you have to grep around

Wow that must have been a really wierd Smalltalk course!

Looking at the example it seems that you were expected to edit and work with file-in format files! That's really wierd - the ordinary thing is to work with the IDE which provides simple ways to find method implementors and senders and refactor and ...
Isaac Gouy
Friday, 18 January 2008 16:01:15 (GMT Standard Time, UTC+00:00)
Okay, no idea if that message got posted...
commenter
Friday, 18 January 2008 16:01:35 (GMT Standard Time, UTC+00:00)
Sheesh
commenter
Comments are closed.