top | item 15211770

Ask HN: Do you mostly program in a non-FP or non-OO style? Why?

69 points| open-source-ux | 8 years ago

Functional and object-oriented styles of programming dominate programming languages today. Are you using a language that has neither of these features? If so, what is the language and why do you use it?

Or are you using an FP or OOP language but rarely use the FP or OOP features? If so, why?

88 comments

order
[+] falcolas|8 years ago|reply
Primarily a Python and Go programmer.

OO: Only rarely, and only where it really makes sense. Most programs I work on are not complex enough to justify the overhead (boilerplate, cognitive).

FP: I use this more, but again, only when I can really justify the added cognitive overhead.

You'll notice the two references to cognitive overhead: I have adapted the "write for a 6th grade level" idiom into programming. I want as many people to be able to pick up the code and modify it as possibly can. I work with everything from interns to decades plus veterans, and my code must be grok-able by both. Pure FP tends to confuse interns, and veterans have a tendency to hate the layers and layers of indirection and abstraction OO brings into a program.

Normal and boring old "an imperative main method with functions" tends to be the least offensive and most understandable to all parties. Compromise r fun.

[+] qorrect|8 years ago|reply
Programming for the lowest common denominator? Something about that sounds wrong.

I generally agree with "use only as much cognitive overhead as needed to get the job done" ( I'm enjoying that term ) - but it seems like a slippery slope that could slowly bring everyones abilities down to the least capable developer.

[+] solipsism|8 years ago|reply
How do you test your code? When a module of code, C, depends on abstraction X, how do you test C in isolation from X?

The common way to do this in OO (and yes this very much includes Go, whose standard library is incredibly OO) is to have C depend on an interface instead of a concrete X. Then you have full freedom to test C very robustly and at different abstraction levels.

So how do you cope with this in your code? "Imperative main method with functions" doesn't sound like it leaves room for proper testing, unless the code doesn't do much.

[+] llogiq|8 years ago|reply
Data scientist/engineer here. I write Java by day, Rust by night and in both I embrace a data-driven design, where I first carefully lay out the data so that it's easy to use within the code. In hot loops, I avoid dynamic dispatch for its runtime cost.

I don't embrace the FP style either because while I generally limit mutation (`final` almost everywhere), I use mutation where it leads to code that is easy to understand, which would be exceedingly "clever" in FP style.

[+] hyperpallium|8 years ago|reply
I mostly use a procedural style (i.e. C like) in java, for working out new ideas in solo projects.

It's simpler, more flexible, less verbose and easier to follow than a full-on OO style. A great example is the early calculatoe e.g. in ed 2 vs 3 of the compiler "Dragon" book: older uses C, later uses OO java... and it's so much worse.

However, OO is great for wrapping up modules of functionality for which you've understood and settled on an informed architecture (or you just need to sweep repetitive boilerplate away).

I think inheritance is just about completely useless (but not quite completely), and (java) interfaces are great - if you have more than one implementation.

Big, multi-person projects are a different story.

I don't use much fp-style, except where recursion is natural (e.g. parser combinators); or for plug-in functions (hardly fp though).

[+] morbidhawk|8 years ago|reply
I was writing a small but semi algorithm-heavy library in C# that didn't rely much on other libraries. I later decided to port it to Java and realized that the more C#-like I had written the original code the harder it was to port. Later when trying to port it to JavaScript I ended up re-writing the C#/Java code to rely less on the standard libraries since each standard library differed so much. At that point my code started to look very procedural in the OO languages possibly similar to what you've been doing in Java.

I came to the realization I didn't even need a lot of the language features for what I was doing and decided to switch it to C to not have to maintain various versions of the library and it was a steep learning curve but I've come to really enjoy the simplicity but powerful capabilities of C.

[+] analog31|8 years ago|reply
Procedural programming is what I learned first (Pascal), and I trust myself to write good code in a procedural style.

I do some microcontroller programming, and it's usually straight C. The hardware registers are all global, and their contents change based on external stimuli, so that kind of rules out the idea of stateless programming.

The earlier versions of Visual Basic had kind of a compromise, where it came with a lot of pre-made objects, and you could create objects if you got the special kit, but the casual programmer was only expected to use objects. I kind of adhere to that idea when I write in OO languages such as Python.

I use OO sparingly when programming Python, often to encapsulate hardware functionality, but then use those objects within programs that still look procedural.

I avoid using inheritance, mainly because I don't trust myself to do it in a maintainable way.

[+] Animats|8 years ago|reply
I've written almost entirely object-oriented code for two decades. My programs have almost no global variables.

I've tried functional programming in Rust, but it's not going well.[1] I don't like the "x.and_then(|foo|).if_even(|bar|).except_on_alternate_tuesdays(|baz|)" style. Rolling your own control structures is not good for readability.

[1] https://github.com/John-Nagle/rust-rssclient/blob/master/src...

[+] nnq|8 years ago|reply
1. "Shallow" OOP - minimal use of inheritance, composition ok but without making a Russian doll with 7+ layers with it.

2. "Grand scale Functional characteristics" - exposed API should try and have "referential transparency" and "composability" (you can write systems with "functional properties" in languages like PHP just fine btw.)... find not much benefit from "small scale / low level" FP.

3. Wrap stateful algorithms & other code rich in mutable variables in either (a) referentiaally transparent functions or (b) shallow objects that make it obvious how and when state changes.

4. Avoid the "islands of functional purity in a sea of objects" pattern like the plague - it results in large scale intellectual masturbation at the small scale, and incomprehensible systems at a large scale, your monadic fantasy is useless when stuck inside the method of a 8-levels-inherited monster object... functional is important on a whole-system level, a 10 line method is easy to understand even if it mutates local variables all over the place

In theory FP would be great at all scales when coupled with a good type system... but I've never got to work on projects in languages like Haskell or Scala and I'm not sure I could handle the cognitive overhead of it.

Oh, and don't use Exceptions, ever!

[+] nnq|8 years ago|reply
On programming languages: It also doesn't matter whether the language has such a good support for functional programming when you don't care about doing in on the small, inside inner-inner-function level, so `map`, `foldr`, functor or whatever... make no much difference. As long as you have the basics, like "first class functions" and "lexical closures", you can do "large-scale functional" programming in languages like Go just fine. It actually feels more refreshing in a minimalist language like this and with a minimalist and explicit type system :)
[+] zaptheimpaler|8 years ago|reply
I use Scala - it can be used or abused to do advanced OOP and advanced FP.

I tend to see programming as writing. The style of writing depends very much on the context and the audience.

I lean towards "basic" FP (immutability/pure functions/composition) but none of the heavy category theory concepts (anything with types that are too complex). Its mostly procedural with a hint of FP.

Most things should be functions, most higher level things (classes/packages) should be primarily ways to bundle related functions.

Prefer to maintain a clear separation between data & operations on data or structures imposed on top of it. I dislike the OOP approach of bundling data + transformations together. Also dislike inheritance because that is baking one particular structure into the definition of data.

[+] morbidhawk|8 years ago|reply
My preference recently for side projects has been imperative/procedural style of programming. I prefer it to OO and FP hands down. To me code is so much easier to read when you don't have clever abstractions everywhere, most code reads line by line and isn't trying to hide anything. I think there is a tradeoff between concise terse code you find in OO/FP that reuses other code vs the long step-by-step procedural code. For me personally I'd prefer longer code that is not reusing a bunch of other functions.

It's almost a weird paradox: OO/FP focuses on reusing code yet imperative/procedural code (ie: C) does not reuse code but is itself the most reusable code. You can't have your cake and eat it too I guess.

[+] jstimpfle|8 years ago|reply
Reusable code may be not the best code. There is probably a lot of redundancy (cross-cutting concerns). Or alternatively, increased interface complexity, to the point where it's easier to just write a custom-tailored version of the code.

I still like to program in C and make my own thin abstractions / "runtime", tailored to the task at hand, and using only minimal dependencies. That way it's much easier to have only essential dependencies, not accidental ones. It's such a relief seeing a couple thousand lines of cleanly modularized C code compile almost instantly.

For example, by putting a char * into a struct definition a dependency on a more clever string type can be avoided. All that it takes is delegating memory management decisions to another place. Which is actually very beneficial, since most code shouldn't be concerned with mutation or especially allocation.

[+] itwy|8 years ago|reply
PHP. Good old procedural PHP. Cleaner than most OOP and FP projects in the wild and I can code large things quickly and easily. The code is very maintainable as well. I even avoid PHP's OOP solutions with the exception of PDO which I wrap in procedural functions.
[+] messe|8 years ago|reply
Physics student here. I write a lot of python scripts/notebooks, which tend to be very imperative in style. They're usually just one-off programs, and there's little in them to be abstracted out. I rarely drop into C, as numba+scipy is usually fast enough.

Other than that, I use Mathematica quite a bit for playing around with ideas. I've tried sympy, and I hoped to switch to it but it's just not as fluid and integrated.

If I'm coding for fun I tend to come back to FP and OO, I'll use either Haskell, Python or CL. I've been meaning to make something using Rust for a while. I'm planning on building a fermentation chamber (and perhaps a kegerator depending on my budget) for homebrewing at some point over the next year; I'm thinking that I might use Rust for the temperature controller.

[+] glup|8 years ago|reply
Similar case here as a cognitive science PhD student... analyses (Jupyter notebooks) are basically imperative but if I need to write a library to support the analysis (which I almost always need to do) then OO.
[+] _0w8t|8 years ago|reply
When I have an option, I program in a procedural style. The code is easier to maintain and follow this way.

For side projects and for small Python code at work recently I have been applying data-oriented programming patterns. So far they worked surprisingly well.

Perhaps this is because one have an overview of the whole program state that is not hidden behind multiple layers of OOP abstractions and there is no mix between data and code, as happens with functional style.

[+] ajarmst|8 years ago|reply
OOP wasn't really yet a thing and GUIs (which I think of as the killer app for OO) were still experimental when I was first learning programming. I started out with Fortran and Pascal on a timeshared mainframe. Probably because of this background, I still find OO languages ungainly, especially the huge libraries that are usually associated. I'm also a bit of a skeptic about the purported value of the OO abstraction, which always seems to cherry-pick from a few problem classes that lend themselves to representation as interacting objects.

While I sometimes teach programming in C# and C++, my main responsibility is our Algorithms and Data Structures courses, for which we've kept using plain old C. From a teaching perspective, it's a great language for teaching fundamental algorithms and data structures. The students are also able to leverage that work into later courses on microcontrollers and embedded systems.

For my own work, I tend to mostly be writing code for somewhat idiosyncratic one-off data processing (I'm currently working on a genetic algorithm for class, student and professor scheduling) or embedded systems. The former I generally work in Common Lisp (SBCL)(although I do keep promising myself to learn enough Clojure to see if I prefer it). This is probably because of the way I think, as I tend to be comfortable building a system from bottom up, moving the data representation from the general facts I start with toward a representation that meets my needs. I actually came to CL pretty late, about a dozen years ago, but it really seems to suit me, possibly because I'm still primarily a command-line person. Being an emacs user certainly was a strong influence, too, although I don't hack elisp very much. I should add that I do often use CLOS, especially when working with more structured data, so I do use some OO, although it's mostly just to provide a more convenient interface to some complicated data type.

For embedded development, I still work almost exclusively in assembler or C, with less assembler every year. I tend to be working on pretty low-powered special-purpose devices, so code reuse and robust interfaces don't add much value, but close control of exactly what the hardware is doing does. This was normal in that domain until comparitively recently, but the power of even cheap devices and the availability of libraries mean that there are a lot more options. I expect that I'll continue to work mostly in C out of familiarity and inertia, but I will admit to having recently bought some Lua books with the intent of trying it with ESP8266.

[+] lj3|8 years ago|reply
> which I think of as the killer app for OO

Was this written in a book somewhere? I keep hearing it from people, but nobody's able to really explain why. OO is terrible for GUIs IMHO.

[+] 5ilv3r|8 years ago|reply
I try to only use capabilities that are common to all languages. Some basic math, basic conditionals, and maybe poking a file or memory address somewhere. I don't give a enough of a crap to get excited for new but short-lived features anymore.
[+] mlok|8 years ago|reply
Same for me. Lately I was wishing there would be a translation matrix for all these basics in every language.
[+] nnfy|8 years ago|reply
Personally, I learned to code in an oop style. I cut my teeth on CPP and then a few years of c#, but these days I work in python.

My problem with non OOP in a language like python is that I have trouble scaling large apps and interacting with large libraries, because without type information enforced by the compiler, there is too much left to my own working memory, compared to a strongly types language built around OOP.

What's more, without rigid encapsulation I feel im exposed to an excess of internal code any time I need to look up a parameter or kwarg. Never mind the trouble of navigating five files feel through aliased method names...

As examples, consider matplotlib or tensorflow. Extremely easy to use once you know where everything is and what params to pass where, but I can't help but feel that it would be easier with stronger OOP.

I feel like I have not yet learned to think in a pythonic manner, but after a few years I'm not sure if I every well. As an aside, I just dont understand how python doesn't cause problems for devs when it scales...

[+] gt565k|8 years ago|reply
I primarily use a declarative language called LogiQL, which is a superset of Datalog. It's basically logic programming. Using predicates and rules.

We have a proprietary database called LogicBlox, that allows us to push all business logic down to the database layer, and almost entirely avoid having a service layer, or at least a very lean one. This allows us to address efficiency problems purely by optimizing database joins between predicates (tables).

Our data is highly normalized (6NF).

http://www.logicblox.com/learn/

[+] lgas|8 years ago|reply
FP. Because it makes most things easier while resulting in software that works more consistently.
[+] rasjani|8 years ago|reply
Last project I did was mainly procedural and that's my default go-to type of structure but OO has its place too. For example in that last one, i had few objects that implemented same functionality but with different data structure. So if I wanted to later on add new data structure, just adding a new class with predefined and partly dynamic features, I'd only need to implement a new class.

For data iteration, i prefer functional style (even in python, even after years list comprehension just feels so wrong).

[+] imh|8 years ago|reply
SQL is neither FP nor OO! It's not a general purpose language though, so it may not be a great answer. It's still amazingly useful and incredibly prevalent.
[+] cratermoon|8 years ago|reply
My current gig has me writing Go, which doesn't do much more than wave a hand at OO to start with, and the codebase I'm working with is particularly un-OO.
[+] tscs37|8 years ago|reply
I mainly write in Go. My adopted approach is to be pragmatic about how I approach my problems.

I kinda tend to start with a OOP style for the data models and a small shake of FP for the functions but change this according to my needs.

There is no one true style for programming, there is only tools for a task and using the best or good enough tool is the only important thing. (Though sometimes it's fun to use the wrong tool and see how it goes)