4 ms·
Why Why Functional Programming Matters Matters
- joe_the_user 17y agoA nice article which gives a high level summary of the issues involves. I like the general idea of "factoring" programs. By outlining the issues well, he also lets me question some of his claims. In a game design where you have important information about a rule smeared all over the object hierarchy, you have very poor separation of concerns. It looks at first like there’s a clear factoring “Baltic Avenue has a method called isUpgradableToHotel,” but when you look more closely you realize that every object representing a property is burdened with knowing almost all of the rules of the game. Hmm, A "noun" or OO language would make each property part of the property class and that would solve the problem so-far as he's articulating it. The thing is, how would a 'verb' oriented language deal with a very specific kind of noun, one which both reacting to general verbs differently and required it's own special verbs. It seems like this special noun would 'smeared' around the verbs to a worse extent. If Baltic Avenue has some weird behavior, it seems cleaner to have it as separate subclass than having it's behavior taken into by various conditionals. Similarly, think about the design of a Chess game. The verbs would be 'move', 'capture'. It seems cleaner to make these verbs into 'messages' or member functions that each piece responds to according to it's class, rather than creating a single method that might call submethods. Still, it's a nice discussion.
- arohner 17y agoThe thing is, how would a 'verb' oriented language deal with a very specific kind of noun, one which both reacting to general verbs differently and required it's own special verbs. It seems like this special noun would 'smeared' around the verbs to a worse extent. If Baltic Avenue has some weird behavior, it seems cleaner to have it as separate subclass than having it's behavior taken into by various conditionals. Think of each individual community chest card. Think of "can I mortgage this property?". Think of "if the reading railroad is not owned, take possession of it." There are a lot of rules in monopoly, and some of them have to do with the combination of several pieces of state: the state of the player, the state of a piece of property, whose turn it is, etc. Trying to handle certain behavior inside the Baltic Avenue subclass might be problematic because you might not have access to some necessary state. And even if you have access to it, getting that state from the baltic avenue class might be a serious violation of concerns. A helpful oversimplification is to say OO "prefers dumb code and smart data", while FP prefers "smart code and dumb data". In an FP monopoly, the board is a set of dumb datastructures. The rules are functions that modify the board. Each community chest card can be a single function, that takes the state of the old board, and returns the state of the new board. The function is simple, it just reaches in and mucks with the single state of the world datastructure. Now your property objects are not weighed down with how to handle community chest card #35. The code is also simpler, because no single class has functions for how to respond to each rule in monopoly. Another extremely powerful aspect of FP is first class functions. The actions a player is allowed to take can just be a list of functions. When players change turns, you can run a function on the list of allowed actions that adds or removes functions as appropriate.
- amalcon 17y agoA helpful oversimplification is to say OO "prefers dumb code and smart data", while FP prefers "smart code and dumb data". This makes a lot of sense, but it seems backwards in a way: FP is as much about the realization that code is data as it is about any specific way of doing things. Your list of functions for "actions a player is allowed to take" certainly seems like "smart data" to me.
- lmkg 17y ago"Code is data" is orthogonal to smart/dumb code vs dumb/smart data, as it's a property of reflective (introspective?) programming languages, not functional ones. You could conceivably use imperative or OOP techniques in JavaScript to construct a string to eval(), but then Dijkstra would shamble out of his grave to give you a very stern glare. An array of functions to invoke is really more like a cute functional way of expressing a complicated switch. "Code is data" refers more to meta-programing, which would be having the language write the functions for you based on a higher-level description.
- amalcon 17y agoI was under the impression that it was neither "macros" nor "first-class functions", but rather something that encompassed both of them: basically, the idea that the programmer shouldn't need to treat one part of the data differently just because the processor does.
- ekiru 17y agoRegarding your chess example, I disagree. Having a "piece moveTo: aPosition" method is much less clean than having a "piece moves" message and a "board moveFrom: somePosition to: anotherPosition" message. Pawn captures would be handled similarly. #moveFrom:to: would check if the piece in somePosition can move to anotherPosition(or if it could capture to that position if the destination is occupied). If so, it moves the piece and handles any capturing. The logic of movement or of capturing isn't a quality of the chess pieces. The ways a piece can move or capture are qualities of those pieces. Having #moveFrom:to: as a message to the game-board allows you to keep all the code related to the way capturing and movement in chess works together, and keep the code for describing the movements of an individual type of piece with that type of piece. It also means that a piece doesn't need to know where it is on the board, or even what board it is on. You could even use a single object for all knights, another for all rooks, and so on without any negative consequences. However, if you do do that, there is a risk of introducing additional complexity in the Board class when it comes to dealing with castling, pawn double initial moves, en passant, etc. Double initial moves could be handled with a message on Pawn(#hasMoved) and using two Pawn objects, one with hasMoved set and one without it. The same could be done for King and Rooks for castling. En passant would probably require keeping an extra instance variable on Board to keep track of double initial moves.
- ptgz 17y ago"do" you know? "for" - it isnt much better. "While" I use the key words I understand "if" it is explicit.
- bitwize 17y agoComing up on news.yc: "Why \"Why Functional Programming Matters\" Matters" Considered Harmful Why "\"Why \\\"Why Functional Programing Matters\\\" Matters\" Considered Harmful" Matters
- cabalamat 17y ago> It is a logical impossibility to make a language more powerful by omitting features, no matter how bad they may be. What does "powerful" mean, in programming lanugages? I can think of three meanings: (1) what it can do. Once a language is Turing complete (call this 1.1), in one sense it can do anything. In another sense (1.2), maybe it can't: I wouldn't attept to write a Unix kernel in Java or a 3-D graphics library in Python because in both cases they are too high level of the task. (2) how easy it is to program in? I.e. the number of programmer-hours it takes to solve a problem in that language. (3) how easy it is to automatically reason about programs written in the language. This includes tools such as compilers, source code coverage tools, etc. Now let's examine the original statement by these 4 criteria. We'll also consider the obverse, i.e. whether you can make a language less powerful by adding features.: 1.1 - if a language is already Turing-complete, removing features won't make it more so. Nor will adding features make it less powerful. But Turing-completeness is a trivial sense, as the article points out. 1.2 - adding eatures can make a language less powerful in this sense, because it can reduce the things it can do. For example, a big complex language with a large standard library might not work on a simple embedded controller, so in that sense it could do less. Or a language might require a certain model of multitasking that means it can't run on certain OS's (e.g. Java couldn't run on early versions of Windows (IIRC either 3.1 or 95 -- I don't remember the details). Or consider that Java is "write-once run anywhere"; adding lots of low level features might imperil this. 2 -- adding features can certainly reduce power here too, e.g. if you have a large C++ program written by a team of programmers each of whom uses a different subset of the language. 3. -- again, adding features can reduce power. For example, in Fortran, an optimising compiler can make assumptions about the code that a C++ compiler can't make because C++ allows pointers to point to anything, e.g.: int foo(int a, int* b){ a = 1; *b = 2; bar(a); /* we don't know here if bar is being called with parameter of 1 or 2 */ } So I think the original proposition is false in practical terms.