Learning Haskell/Python makes you a worse C# programmer
lukeplant.me.uk
lukeplant.me.uk
string.Join("\n",
from elem in myList
where elem.Description != ""
select elem.Description);
Note how mind-numbingly close this is to the Python: "\n".join(foo.description() for foo in mylist
if foo.description() != "")
I also think it's considerably easier to read than the foreach loop.Would it be irresponsible to speculate that this article is directly responsible for the inclusion of Linq in C#? It would be irresponsible not to speculate!
http://research.microsoft.com/en-us/um/people/emeijer/papers...
Now everybody knows that type inference, list comprehensions and lambda functions can reduce code. Even javers.
in c#3.0 we write
string.Join("\n", mylist.Select(x=>x.Description()).Where(x=>x != "").ToArray());
and now string.Join("\n", mylist.Select(x=>x.Description()).Where(x=>x != ""));"Method names should be verb phrases" is one possible convention, but it's not the only convention. If you can get better code by violating that convention, then the convention is, in that instance, wrong. Using verb phrases for function names is more of a procedural programming technique that doesn't always translate to object-oriented programming. In this particular instance, having a more declarative interface is more readable.
On the implementation side, if you just want to expose a variable then attributes are fine. Outside of your object, though, who cares whether or not "length" is an attribute? Maybe your object is encapsulating a lazily-evaluated database relation, at which point "length" would generate a SELECT COUNT query. It still fulfills the contract of "an object that has a length", and you don't want to get in the business of defining different interfaces for "an object that has a length cached in an instance variable" and "an object that has a length that is calculated dynamically".
The properties of an object are best expressed with noun phrases regardless of their implementation.
It's much simpler and more effective to think of objects as things that respond to messages. So instead of thinking it as asking the object to perform "where" or "length", think of it as sending the message "where" or "length" to the object and potentially receiving a response. This way you can expose more flexible and declarative interfaces, and let the object worry about which properties it computes on demand and which properties it caches or stores in instance variables.
You do have to consciously do this in C-derived languages, though. But it's easily possible.
If anything, it introduces unnecessary semantics to syntactically distinguish between messages that are responded to with instance variables and messages that are responded to with function calls.
Deleted comment
I'm thinking that complaint is that something like (e.g.) "Filter" would mean the same thing and be a verb describing the action being taken.
from http://msdn.microsoft.com/en-us/library/bb397926.aspx
"Language-Integrated Query (LINQ) is a set of features introduced in Visual Studio 2008 that extends powerful query capabilities to the language syntax of C# and Visual Basic. LINQ introduces standard, easily-learned patterns for querying and updating data, and the technology can be extended to support potentially any kind of data store. Visual Studio includes LINQ provider assemblies that enable the use of LINQ with .NET Framework collections, SQL Server databases, ADO.NET Datasets, and XML documents."
We just allowed some F# code into Kiln. On the one hand, it was vastly simpler than the C# code it replaced. On the other hand, we had to rearchitect our solution layout to handle changing the build order, which we in turn had to do so that the F# code could be sanely usable from the C# code and vice-versa, which in turn required writing a lot of call-site boilerplate and type converters (from C# to F# types). Add in that the CLR is simply not as optimized for F# as for C# (or vice-versa, depending on how you want to view things), and it's not exactly a situation where you can simply say, "Well, F# is better than C# at expressing this problem, so let's use it here."
I want to be really clear on this: I don't think these problems are any worse on the CLR than they'd be on the JVM or with native tools (e.g., OCaml calling C or vice-versa). In fact, they're better in many ways: you have the BCL for your primitives, rather than the native C ABI (for native), and you have a VM that is legitimately much less tied to an individual language than the JVM, which makes things like tail-recursive languages a lot simpler. But I think the right way to regard Foo# languages is more-or-less the same as any other language: unless you can write the entire project in Foo#, think hard about whether the cost of interfacing between Foo# and C# is worth it to your project. Most of the time, it isn't.
Also consider that HR departments and some engineers falsely assume that it is hard to hire people to work on your project if you use F#, whereas c# has enough similarities to other languages that it is easy for people to get up to speed.
Do you disagree that C# has similarities to other languages? C# is based on Java, which is somewhat based on C++. Basically anyone who does a CS course learns one of these. In comparison, I don't know any programs that use Haskell, oCaml, scala, or ML (I had a single class in which I had to use ML fora single project). What I mean to say is, functional programming is not widely taught. I don't think this is controversial.
Do you disagree that any person that is reasonably smart and that you'd want to hire could become productive in c# within a few days, given that they've used java or C++ before. This is a super-low risk gamble. I don't think this is controversial.
The only indicator that someone can become productive in F# is that they have experience in one of F#, Lisp, ML, Haskell, etc. I don't think this is controversial.
Hiring people is hard. Maybe you haven't been involved in the process, but you have to interview hundreds of people just to find that one person who is smart, is a culture fit in your company, and has enough self-discipline and a high-enough level of consciousness to go about their work in a pragmatic and intelligent manner.
Now imagine that you are CTO of a new company and you are deciding between c# and f#. If you startup becomes successful, you'll have to quickly ramp up in hiring engineers. If your startup doesn't become successful, you'll quickly have to ramp up in having someone else hire you.
Assuming we are a rational person, that is we are doing a startup in the hopes that it will be successful, then our plans will facilitate the hiring of many engineers.
Fast forward to when we need to hire many engineers. Also, remember you don't have loads of time to spend doing this, because you're the CTO of a startup and you have shit to do. Also, remember it's hard for startups to hire because 1) risk and 2) you aren't google.
Now imagine taking your pool of candidates and reducing it by 99%.
Java developers are sold to customers as expert .NET consultants, because on management eyes C# is just like Java! :(
If your Java developers have problem picking up C# on the go and doing quality job within few short weeks with the assistance of one or two experienced C# devs as team leads, I doubt that they are good Java developers at first place.
You can even remove functional from the sentence. Powerful features of languages like Python and Lisp don't get you more power than languages like Java. They give you more power per unit of effort.
Python didn't drag my day job down. Instead, it gives me the understanding of what Java's shortcomings are and why IDEs and frameworks exist to cope with them.
It also changed the way I looked at design patterns. Before I knew Python, they were pretty intimidating. Now, I look at a strategy pattern implementation and find it more a cute attempt to compensate for something than anything else.
But if you've learned a whole range of languages you'll try to come up with more elegant solution. He tried that, but as gecko pointed out the errors were not in trying, but rather in his results.
I work in a C# dev house now, and boy what is considered a good solution there (and in their contractors works) is so sad I don't even know what to call it.
But then, you look at the latest c# version and it has quite a few interesting features, people just don't use it. My guess is that they've just been doing it since c# 2.0. And the fact that c# is not really made for web development, which is what it seems to be most taught doesn't really help either.
join "\n", map { $_->{description} } grep { $_->{description} ne "" } @mylist;
sorry, every time i see something like this, i just can't resist to post code in Perl. =) @list.map(*.description).grep(?*).join("\n")Instead of chaining methods, one could also use
# p5 style
join "\n", grep ?*, map *.description, @list;
# dataflow style
@list ==> map *.description ==> grep ?* ==> join "\n";
join "\n" <== grep ?* <== map *.description <== @list; $ perl6
> sub infix:<J> ($sep, @list) { @list.join($sep) }
> sub prefix:<J,> (@list) { @list.join(',') }
> ':' J <one two three four>;
one:two:three:four
> J,<five six seven eight>;
five,six,seven,eightC# has a tremendous potential for functional programming. There's some features that make a pure functional style easier and prettier in haskell, but C# has plenty of potential.
The title is total link bait. I clicked because I know there are things to write about - like pervasive nulls and mutable-by-default variables to begin with. There really are things to complain about! But the actual contents of the article are infuriatingly obtuse.
The fact that 39 people found this interesting in 2012 just demonstrates how ineffective the entire hacker news concept really is.
C# is an amazingly designed multiparadigm language with excellent tooling that works in plenty of OS and devices. If it will come by google the open source world will be wet already. Having an ideology is ok but shouldnt be confused with technical merits. Some examples:
IQueryabe<T> and expression tress let you write expressive queries that run on the database but have compile-type checking. Amazing for mantaining big datacentric apps.
Async/await let you write complex asynchronous code as if it where usual imperative one. With for, try catch, etc... The compiler changes it for you.
And all this on a real language that runs fast and you can use in your work to build phone apps, web apps, win apps and also, but not just, compilers and authomatic theorem proving applications.
I like using functional methods in Java to implement DSLs but the guava docs are right when they say you shouldn't be ashamed to use a for loop from time to time in Java.
In this case, just using C# a bit more idiomatically can go a long way:
var descriptions = new ArrayList(mylist.Length);
foreach (var foo in myList)
{
if (foo.Description == "") { continue; }
descriptions.Add(foo.Description);
}
return String.Join("\n", descriptions);
The names the author gives to his variables are the first indicator that he just isn't really in a C# mindset.Here's a slightly more idiomatic C# 2.0 (i.e. sans var goodness)
ArrayList descriptions = new ArrayList(mylist.Length);
foreach (Foo foo in myList)
if (foo.Description != "")
descriptions.Add(foo.Description);
return String.Join("\n", descriptions);Also, do you think leaving out the braces is idiomatic? I think it looks really pretty but I don't like it at all, it is too brittle.
On the other hand, I think the risk of making the code slightly more brittle is worth it if it makes it much more pleasant to read. Whenever I see a for/foreach followed by a single statement then I know that the code is doing a simple projection (i.e. Select in Linq or SQL parlance). If it’s a for/foreach followed by an if statement followed by some other statement (as in the above code) then I know it’s a simple filter and projection (i.e. Where and Select).
But I wanted to illustrate your larger point, which is that C# programmers shouldn’t be so quick to use functional idioms since imperative code can not only look just a pretty, but it’s almost always slightly more performant since it doesn’t imply as many allocations and indirections.