You seem to be intentionally taking that Clojure code out of context. The refactored of version of that code, which compares much more favorably with your C# 3.0 version, was given as:
On the contrary, I think that the C# code the author presented was unfairly IN CONTEXT. It showed using statements, a namespace, the program entry point, and other boilerplate. While I agree that C# has a non-trivial class boilerplate and non-zero function boilerplate, the Clojure you quoted doesn't even show any function boilerplate (defn foo [args] body)
I compared a C# 3 expression to a Clojure expression.
And that bit of Clojure that you quoted uses helper functions which are not defined. The C# version of that is:
(from asset in assets
let liquidValue = GetLiquidValue(asset)
where DoubleMargin(asset, liquidValue)
select liquidValue).Sum()
Clojure is a great language, but this article unfairly bashes C#, which is also a great language.
agreed. i think his C# code is intentionally obtuse or something. and the 'refactored' version of the Clojure code with the gnarly bits removed is missing the logic to actually perform the calculations.
speaking of functional, i'm new to Haskell, but wouldn't it just be
f x = sum [v | (y,z) <- x, let v = y*z, v >= z*2]
assuming the argument is a list of tuples in the form (SDFactor, productionCost)
you could also foldl if you don't trust the compiler to optimize the extra list iteration away.
i didn't really like the article. the tone was really grating. probably look elsewhere if you want some inspiration on functional programming style
“Every line of code, whether it be PHP or Clojure has roughly the same potential for a bug. But 20 lines of Clojure may sometimes translate into 1000 lines of PHP.”
Not PHP, but C:
int x = 6;
I'm pretty confident about that one. A lot of those 1k lines of code will be "stating the obvious". I don't think it's fair to imply that the probability of a fault in a line of C code is anywhere near the probability of a fault in a line of Clojure.
I can point to a Clojure line that has similar characteristics (and I don't even know Clojure):
(+ 1 1)
Done. Clojure's awesome, right? No errors. That rocks, huh?
No. Even that line has the potential for errors:
1. You could have a typo (int z = 6; int x = 7;)
2. You could have misunderstood the requirements (it should actually be float x = 6.5)
The only possibility you excluded with this trivially simple line is:
3. An error in how you used your own tools (easier to imagine if the line involved pointers).
Part of the difficulty of debugging is, you don't know which lines have errors in them. If you have 1000 lines, you potentially have to review them all to find the bug. If those lines are poorly compartmentalised, so that you can't heuristically find your way to the likely location of the bug, that is doubly the case. Conversely, if you only have 20 lines of code, then you only have 20 lines to read before you've definitely seen the line with the bug (whether you recognise it is another matter, which has more to do with experience, capability, and the clarity of the code).
Intention-revealing code does tend to be much, much clearer, though. (although I'll grant you it's possible to obfuscate code with malevolent intent).
Blind Clojure love. I like how right as he starts to approach the specific problems that Tim Sweeney and Epic have to deal with in handling what is fundamentally a mutability problem(unified game state), he sweeps them under the rug so that he can go back to talking about how functional code is beautiful, disregarding that it is insufficient for the problem at hand.
"I’ve received about 6 comments from C# developers all giving me their take on a better version of the liquid-value code above. A couple of them using Linq, which simplifies the code substantially. I’ve taken a drastic step in deleting all those comments — sorry guys!!"
sigh OK, clearly this guy is not worth attempting to have intelligent discourse with. What good are comments if you just delete those from anyone who disagrees with you?
@snprbob86: I don't mind you moving comments from my blog to HN, but I do mind you misquoting and thereby lying publicly - it's not good for you and it's not good for me.
Here the full quote:
"Hi all — I’m serving up the first comment!
I’ve received about 6 comments from C# developers all giving me their take on a better version of the liquid-value code above. A couple of them using Linq, which simplifies the code substantially. I’ve taken a drastic step in deleting all those comments — sorry guys!!
Not because they didn’t present valid points, but because they entirely missed the point — I tried to spell it out with the K example — We’re discussing principles here, not code examples. I have no doubt that my rusty C# can be written in a more idiomatic sense, using better libraries etc. But thats much beside the point. The point is, that while the language so freely permits and even encourages me to code that way — I will end up seeing that type of code in my systems. If I had the privilege of hiring a team of superior geniuses and unspeakable coding skills, then sure, they might consistently produce rock solid functional code even in C# — but that’s not a real world scenario.
So lets stick with the principles. And if anybody does provide examples, please connect them with something discussed in the post. That makes for a better discussion than just swapping code.
Thanks to all for taking the time, sorry for being so harsh
/Lau"
Not reproducing the full comment does not constitute a misquote.
Using Clojure doesn't enable you to magically write perfect code. You posted well written Clojure and poorly written C#. You can write poor code in any language.
If you wished to remain on the topic of imperative vs functional, you should have avoided phrases like "using C# as the tool has added a huge degree of ceremony". You made a direct attack on the language, not on the coding style. You also make significant mention of the number of lines of code, but it seems as though you have intentionally included boilerplate to make your point. Being misleading and deleting comments are not ways to make an effective case for your cause.
EDIT: Oh, and on the actual subject of functional style. I still much prefer the C# approach as it reads in order you perscribed:
1) calculate liquid value of each item
2) filter candidates
3) accumulate value
(from asset in assets
let liquidValue = GetLiquidValue(asset) // 1
where DoubleMargin(asset, liquidValue) // 2
select liquidValue).Sum() // 3
sum(liquid_value # 3
for liquid_value, asset in assets
(get_liquid_value(asset), asset # 1
for asset in assets)
if double_margin(asset, liquid_value)) # 2
As they say, you can write fortran in any language, even Clojure if you try hard enough.
Writing rock-solid functional code in C# is not nearly as hard or as strange as you seem to think. If it isn't a real-world scenario for you, that's just because you aren't interacting with the right C# developers. For starters, you could listen to the 6 comments (six? and you still say that it's not real world?) that were posted.
14 comments
[ 3.0 ms ] story [ 38.1 ms ] threadI compared a C# 3 expression to a Clojure expression.
And that bit of Clojure that you quoted uses helper functions which are not defined. The C# version of that is:
Clojure is a great language, but this article unfairly bashes C#, which is also a great language.speaking of functional, i'm new to Haskell, but wouldn't it just be
assuming the argument is a list of tuples in the form (SDFactor, productionCost)you could also foldl if you don't trust the compiler to optimize the extra list iteration away.
i didn't really like the article. the tone was really grating. probably look elsewhere if you want some inspiration on functional programming style
Not PHP, but C:
I'm pretty confident about that one. A lot of those 1k lines of code will be "stating the obvious". I don't think it's fair to imply that the probability of a fault in a line of C code is anywhere near the probability of a fault in a line of Clojure.I doooo like Clojure though :)
(+ 1 1)
Done. Clojure's awesome, right? No errors. That rocks, huh?
No. Even that line has the potential for errors:
The only possibility you excluded with this trivially simple line is: Part of the difficulty of debugging is, you don't know which lines have errors in them. If you have 1000 lines, you potentially have to review them all to find the bug. If those lines are poorly compartmentalised, so that you can't heuristically find your way to the likely location of the bug, that is doubly the case. Conversely, if you only have 20 lines of code, then you only have 20 lines to read before you've definitely seen the line with the bug (whether you recognise it is another matter, which has more to do with experience, capability, and the clarity of the code).Intention-revealing code does tend to be much, much clearer, though. (although I'll grant you it's possible to obfuscate code with malevolent intent).
There is a place for mutation (certain algorithms absolutely require it), in spite of the obvious advantages of immutable+functional programming.
"I’ve received about 6 comments from C# developers all giving me their take on a better version of the liquid-value code above. A couple of them using Linq, which simplifies the code substantially. I’ve taken a drastic step in deleting all those comments — sorry guys!!"
sigh OK, clearly this guy is not worth attempting to have intelligent discourse with. What good are comments if you just delete those from anyone who disagrees with you?
Here the full quote: "Hi all — I’m serving up the first comment!
I’ve received about 6 comments from C# developers all giving me their take on a better version of the liquid-value code above. A couple of them using Linq, which simplifies the code substantially. I’ve taken a drastic step in deleting all those comments — sorry guys!!
Not because they didn’t present valid points, but because they entirely missed the point — I tried to spell it out with the K example — We’re discussing principles here, not code examples. I have no doubt that my rusty C# can be written in a more idiomatic sense, using better libraries etc. But thats much beside the point. The point is, that while the language so freely permits and even encourages me to code that way — I will end up seeing that type of code in my systems. If I had the privilege of hiring a team of superior geniuses and unspeakable coding skills, then sure, they might consistently produce rock solid functional code even in C# — but that’s not a real world scenario.
So lets stick with the principles. And if anybody does provide examples, please connect them with something discussed in the post. That makes for a better discussion than just swapping code.
Thanks to all for taking the time, sorry for being so harsh /Lau"
Using Clojure doesn't enable you to magically write perfect code. You posted well written Clojure and poorly written C#. You can write poor code in any language.
If you wished to remain on the topic of imperative vs functional, you should have avoided phrases like "using C# as the tool has added a huge degree of ceremony". You made a direct attack on the language, not on the coding style. You also make significant mention of the number of lines of code, but it seems as though you have intentionally included boilerplate to make your point. Being misleading and deleting comments are not ways to make an effective case for your cause.
EDIT: Oh, and on the actual subject of functional style. I still much prefer the C# approach as it reads in order you perscribed:
1) calculate liquid value of each item
2) filter candidates
3) accumulate value
Compared to the Clojure which reads: or the Python which reads:Writing rock-solid functional code in C# is not nearly as hard or as strange as you seem to think. If it isn't a real-world scenario for you, that's just because you aren't interacting with the right C# developers. For starters, you could listen to the 6 comments (six? and you still say that it's not real world?) that were posted.