Live data from Hacker News

Destroy All Ifs – A Perspective from Functional Programming

degoes.net

61–70 of 226 posts

Re: Destroy All Ifs – A Perspective from Functional Programming

#61

This whole campaigned is misguided. "Bad IFs" are a code smell, and they're being scapegoated when the real problems are management demanding that simple hackish prototypes & tests be deployed into production, management that doesn't allow time for refactoring, and poor programmers who think that "bad IFs" are good code. But the main site also doesn't do any reasonable job of defining what a "Bad IF" even is. The cru…

I think that aiming at the management of the coders and the business users is putting the emphasis in exactly the right place. Once we get to womdering if eliminating IF stmts will help, we have passed by so many opportunities for 10x value delivery.

The "technical debt" metaphor gets so much better if you take the analogy more literally than most people do. Like for financial debt, the optimal amount is not necessarily zero. Oftentimes taking on or carrying debt allows you to generate more profit than you could by avoiding it or paying it down.

That said, most places I've worked manage it poorly. Few people really understand that, just like financial debt, it's something that needs to be taken on and managed in a mindful and deliberate manner.

Re: Destroy All Ifs – A Perspective from Functional Programming

#62
The first problem is that the "match" function is considered in the first place. It's too general. It should only be used in higher order constructs where its flexibility is actually needed.

Second: The enum based refractor is actually valuable and fine IMO. If you need string functions, stop there.

Now, shipping control flow as a library is a cool feature of Haskell. But, if those arguments are turned into functions, the match function itself isn't needed! It just applies the first argument to arguments 3 and 4, then passes them to the second argument.

match :: (a -> b) -> (b -> b -> Bool) -> a -> b match case sub needle haystack = sub (case needle) (case haystack)

Does that even need to be a function? Perhaps. But if so, it's typed in a and b and functions thereof, and no longer a "string" function at all. And, honestly, why are you writing that function?

Typing it out where you need it is typically less mental impact, because I don't need to worry about the implementation of a fifth symbol named "match."

sub (case needle) (case haystack)

Re: Destroy All Ifs – A Perspective from Functional Programming

#63
post #6

The idea that each type has its own control flow primitives is bothersome. It's taken over Rust: argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse:: ().map_err(|err| err.to_string())) .map(|n| 2 * n) I'm waiting for date.if_weekday(|arg| ...) Reading this kind of thing is hard. All those subexpressions are nameless, and usually comment-less. This isn't pure functional progra…

date.if_weekday looks like something one would find in Smalltalk class library, but (at least for GNU Smalltalk) only such construct I've found is this: http://www.gnu.org/software/smalltalk/manual-base/html_node/...

Re: Destroy All Ifs – A Perspective from Functional Programming

#64
post #5

Define true as a lambda taking two lazy values that returns the first, and false as one that returns the second, and you can turn all booleans into lambdas with no increase in code clarity. The straw man in the post - talking about a case-sensitive matcher that selectively called one of two different functions based on a boolean - is indeed trivially converted into calling a single function passed as an argument, but…

Someone else addressed the details of your counter argument, but I'd like to respond to it generally. It seems like every time someone writes an article on how to write better code, there are responses about how it doesn't make sense when taken to some logical extreme, or some special case, as if that invalidates the argument. (FP techniques in particular seem to provoke this.) But code design is like other design di…

Reading this article I immediately saw a couple of drawbacks. Since then I've thought of a few more. But several of the points made were not lost on me. This article made me think a bit, and I'm still thinking about it. That's worth something right there.

To anyone out there who clicked through to these comments and is thinking it's not worth reading the article, please go ahead and read it. It's short enough. You may or may not use fewer if-statements in the future, but it might give you a better sense of why you choose to do things one way over another.

Re: Destroy All Ifs – A Perspective from Functional Programming

#65
post #6

The idea that each type has its own control flow primitives is bothersome. It's taken over Rust: argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse:: ().map_err(|err| err.to_string())) .map(|n| 2 * n) I'm waiting for date.if_weekday(|arg| ...) Reading this kind of thing is hard. All those subexpressions are nameless, and usually comment-less. This isn't pure functional progra…

I don't agree here at all. The methods you show operate on an Optional, and it's incredibly common to perform those kinds of comparisons so it makes sense that they have convenience methods. This is not at all comparable to something like if_weekday.

This has not "taken over" rust. Result is another type that does this, but this makes sense for the same reasons.

Re: Destroy All Ifs – A Perspective from Functional Programming

#66

Earlier quoted context omitted.

Someone else addressed the details of your counter argument, but I'd like to respond to it generally. It seems like every time someone writes an article on how to write better code, there are responses about how it doesn't make sense when taken to some logical extreme, or some special case, as if that invalidates the argument. (FP techniques in particular seem to provoke this.) But code design is like other design di…

The thing is that the tone of the article seems to suggest taking such an extreme: I mean, an "anti-if " campaign? There's like, only one sentence of concession near the end towards those unconvinced by the argument.

Absolutely agree - if a campaign spouts "Destroy All Ifs" that kind of sets the tone for the discussion...

Re: Destroy All Ifs – A Perspective from Functional Programming

#67

This is the starter code: publish :: Bool -> IO () publish isDryRun = if isDryRun then do _ This would be nicer if you could do multiple functions with pattern matching. In Elixir this would be: @spec publish(boolean) :: any def publish(true = _isDryRun) do _ = unsafePreparePackage dryRunOptions IO.puts "Dry run completed, no errors." end def publish(false = _isDryRun) do pkg = unsafePreparePackage defaultPublishOpti…

Pattern matching is just as explicit as an if loop. In languages that implement it for null values, it is just as explicit as typing "if (foo == null)" in an imperative language. You have to think about it, and type just as much code to deal with it, as you would in a language without pattern matching.

The only upside to pattern matching that I can see is that you are forced by the compiler to match all possible inputs and check for nulls in some languages, which can help you avoid null pointer exceptions and such. But you haven't encapsulated anything, or saved yourself any thinking or typing, by using pattern matching. You've basically turned every function into a switch statement. It's vastly overrated.

Re: Destroy All Ifs – A Perspective from Functional Programming

#68
post #43

Often times when I read about "ideal" ways of programming, I'm curious if it's ever implemented in a production code base built by a team.

Me too. Particularly because every programmer has their own idea of what a "right"/ideal style of programming is. Here, apparently, we must not use conditionals. The more I write code the more I realize that the entire purpose of the code is to have some effect on reality, and the more reliably it can do this, the better the code. I find I code a lot better without design principles, because trying to remember which…

Not functional code though. The aim of functional code is to be side-effect free, and affecting reality really gets in the way of that.

/snark, but articles like this really do fall into that trap...

Re: Destroy All Ifs – A Perspective from Functional Programming

#69

I recommend Bob Harper's essay on "boolean blindness": https://existentialtype.wordpress.com/2011/03/15/boolean-bli... An excerpt: > The problem is computing the bit in the first place. Having done so, you have blinded yourself by reducing the information you have at hand to a bit, and then trying to recover that information later by remembering the provenance of that bit.

Can't that argument be extended to, say, uint8_t, and from there to all sorts of computed values?

Re: Destroy All Ifs – A Perspective from Functional Programming

#70
post #6

The idea that each type has its own control flow primitives is bothersome. It's taken over Rust: argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse:: ().map_err(|err| err.to_string())) .map(|n| 2 * n) I'm waiting for date.if_weekday(|arg| ...) Reading this kind of thing is hard. All those subexpressions are nameless, and usually comment-less. This isn't pure functional progra…

The annoying part there is the repeated "|x| x.". Rust should have syntax to reference a method of an object, instead of having to write a wrapper. So it'd look like .map_err(???.to_string()).
Post reply on HN