4 ms·
>"I have to write out some 3 line loops that in other languages are one line" I think every vim, emacs and decent IDE user would say "I has a text editor. Your
by officemonkey 14y ago
>"I have to write out some 3 line loops that in other languages are one line"
I think every vim, emacs and decent IDE user would say "I has a text editor. Your argument is invalid."
- stouset 14y agoOn the flip side of this argument, code should be optimized for reading, not writing. Short, idiomatic code IMHO optimizes for reading. Code like array.map(&:to_s) parses instantaneously. Whereas the procedural equivalent strings = [] for (element in array) strings.push element.to_s end requires scanning through the loop to extract out the logic specific to this case. And it's easy to accidentally overlook something when mentally ignoring the "boilerplate". Not to make a mountain out of a molehill, and not commenting on Go specifically, but the extra "cost" of this style of code adds up when the language itself gets in the way of using high-level abstractions. Methods that are three meaningful lines long are inherently more understandable than equivalent methods that are twelve. Multiply this cost across an entire class, file, and/or project, and it can have a significant impact on one's ability to grok the expected behavior.
- pacala 14y agoOn the flip side, I had to scratch my head on what "&:" is supposed to mean. Or perhaps it's "&" ":". I know, I'll Google it </yeahright>. More seriously, "for ..." maps into "map", "foldl", "foldl'", "foldr" and perhaps other constructs. They do pretty much the same thing, but I don't necessarily see a real cognitive advantage of either style.
- epochwolf 14y agoThe language is ruby. array.map(&:to_s) eventually means array.map{|str| str.to_s } As I understand it, the & means convert a variable to a code block. If the object already is a callable object (proc or lambda) ruby doesn't need to do anything to pass it through. Symbols (:to_s) aren't callable so ruby calls the to_proc method on it. The rails framework addd this for Ruby 1.8. The code is below. # File activesupport/lib/active_support/core_ext/symbol.rb, line 10 def to_proc Proc.new { |*args| args.shift.__send__(self, *args) } end
- Falling3 14y agostouset is obviously not arguing that the ruby version with "&:" is immediately obvious to any programmer. The point is if you know ruby, you will understand that line a lot quicker than the second example.
- pacala 14y agoWhat is the "fold" variant in Ruby? Maps are trivial either way, but folds are a pita in my functional programming experience.
- bjeanes 14y ago[1, 2, 3, 4, 5].reduce(0, &:+) #=> 15 Which is short hand for: [1, 2, 3, 4, 5].reduce(0) { |memo, item| memo + item } #=> 15
- dan-k 14y agoWith reduce you don't even need to use the & notation, it has that syntactic sugar built in, so you can just do this: [1, 2, 3, 4, 5].reduce(:+)
- pacala 14y agoYes and no. In practice, you're going to fold into a different domain, which causes the types of the reduce function arguments to be different. Moreover, you are not going to have your reduce function conveniently in a library. You are going to have to write a loop body. At which point, choosing a block over a for loop becomes purely religious.
- krichman 14y agoDifferent domain is fine. [1,2,3].reduce([], &:unshift) #=> [3,2,1] I don't see a problem with writing a for loop, but I think it's not as composable and it can be a little harder to read. So I don't think it's purely religious but it's close to that.
- nightski 14y agoIt's bigger than that. You are separating the how from the what. Sure you could compute a map with a for loop. Or you could compute it in parallel across 1000 threads. Not only that, map is composable. Something a for loop never will be.
- pacala 14y agoFor loops have been parallelized for quite a while. Having a dataflow analysis tell apart a "map" loop from a "fold" loop is quite trivial once you have the framework in place (aliasing not withstanding). Heck, Fortran is all about for loops and it's the language for parallel computations. http://software.intel.com/en-us/articles/automatic-parallelization-with-intel-compilers http://software.intel.com/en-us/articles/automatic-paralleli...
- nightski 14y agoI am aware but it misses the point. Parallel computation is just one example. What about traversing trees? Graphs? Any functor? Any compiler directions to automagically make the for loop traverse those? And that does not even address the issue of composability - which is even more important. Map fusion?
- pacala 14y agoBottom up tree traversal doesn't require an explicit for loop as long as the language supports first class functions. bottomsUp(node) { recurseChildren(node, &bottomsUp); switch (node.id) { case FOO: break; case BAR: break; } } At the end of the day the actual code (the switch) is what matters, and the "glue" can be made a couple of lines either way. PS. On a separate language feature, I like match with algebraic datatypes more than switch, but I don't know if Go has match. Go Rust!
- Myrmornis 14y agoI think a list comprehension is clearer than mapping some sort of lambda construct.
- rat87 14y agoyeah in python it would be [str(x) for x in lst]
- yawaramin 14y agoIn more modern (idiomatic) Python you would use a generator expression so: strList = (str(x) for x in lst)
- voltagex_ 14y agoI've seen the for x in lst syntax before, but where should I start to learn about generators?
- frio 14y agoFor list comprehensions, it's the same syntax, but in ()s rather than []s. A generator will be lazily evaluated (so until something tries to get a value out, nothing is computed) and can only be iterated through once. That's pretty much the only differences in that case. There's more complex generator stuff you can do (ie. using the ``yield`` syntax inside functions), but unfortunately I don't know a good resource for that off the top of my head :).
- Myrmornis 14y agoHi yawaramin, there's nothing less modern or idiomatic about list versus generator comprehensions in python. You would use a generator if you want to limit maximum memory usage, and/or if you know that the iterable only needs to be consumed once.
- lobster_johnson 14y agoThe problem with redundant code is usually not editing, it's bugs. More code statistically corresponds to a higher number of bugs.