"…mais ce serait peut-être l'une des plus grandes opportunités manquées de notre époque si le logiciel libre ne libérait rien d'autre que du code…"

Programmation : python versus C#3

Posted by Noam sur janvier 7, 2008

Quelques exemples de code Python versus C#3:

http://brad.livejournal.com/2354680.html (« Cet article permet de comparer l’écriture d’un programme simple entre différents langages: Tcl, Ruby 1.8, Ruby 1.9, C#3, Perl. On apprend aussi que chez Google Python est un langage bien employé: « Google has a shitload of code and infrastructure. Google also has a shitload of engineers that altogether know a shitload of languages. If every engineer were allowed to write in his/her favorite pet language of the week, the necessary explosion of substandard bindings for each library * each language would be unmaintainable. Given that Perl/Python/Ruby are all effectively the same, it makes sense to standardize on one. Python has the right mix of learnability, readability, industry/community support, etc. I don’t object to having to write in Python… it makes a ton of sense

C# Code

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;public class AnagramNames {
 public static void Main(string[] args) {

 	var names = from name in File.ReadAllLines("dist.male.first") select name.Split(' ')[0];
 	var pairs = from pair in (
 		from name in names group name by SortCharsInString(name)
 	) where pair.Count() > 1 select pair;

foreach (var pair in pairs) {
 		Console.WriteLine(String.Join(",", pair.ToArray()));
 	}
 }

 public static string SortCharsInString(string s) {
 	char[] arr = s.ToArray();
 	Array.Sort(arr);
 	return new string(arr);
 }
}

Python Code

#!/usr/bin/python
by_anagram = {}
for name in [l.split()[0] for l in open("dist.male.first")]:
        by_anagram.setdefault("".join(sorted(name)), []).append(name)
print "\n".join([" ".join(n) for n in by_anagram.itervalues() if len(n) > 1])

http://www.25hoursaday.com/weblog/2008/01/02/DoesC30BeatDynamicLanguagesAtTheirOwnGame.aspx(« Un article comparant C#3 et Python: Does C# 3.0 Beat Dynamic Languages at their Own Game? 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

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

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

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. « )

Laisser un commentaire