Page 1 of 2

Imperative vs. Functional programming

Posted: Thu Sep 09, 2021 9:45 pm
by Seasoft
Even though the theory of programming paradigms is still abstract for me right now, I wonder about this. I dipped into a Haskell tutorial, a functional programming language, and I don't know how to completely describe it but so far Haskell looks like a beautiful language. Even though it looks like it's more designed for problems working with lists and other "raw" datum and number-oriented tasks rather than games or 3D graphics objects. And the process to install the platform was a bit painful.

Re: Imperative vs. Functional programming

Posted: Fri Sep 10, 2021 8:34 am
by bloodline
Beauty is in the eye of the beholder. Probably to die to my age, and how long I’ve been programming for, I find functional languages to be clumsy, awkward, and without question very ugly.

Very few languages will ever be as beautiful as C. :)

Re: Imperative vs. Functional programming

Posted: Fri Sep 10, 2021 9:52 am
by nullplan
bloodline wrote:Very few languages will ever be as beautiful as C. :)
I wonder if I should just link to the IOCCC and leave it at that. Personally, I know that good programmers can write FORTRAN in any language. The language is but the canvas, it is the painting created on it that can be beautiful. Although an empty canvas is also beautiful, in a minimalist sort of way, it is not terribly high-effort. And won't really blow your socks off if you hang the Mona Lisa next to it.

Back to the topic. As in any language, you can write awesome code in Haskell, and you can write terrible code in it. I lack the experience to distinguish the two at this point, which is why I stick to C. But I must say, functional style of programming is certainly nice for some things. How many "any" and "all" loops has each of you written in your life? Too many to count, I would wager.

It's just that functional programming is not for me, because I am a very top-down thinker: Give me a problem, and I will deconstruct it into smaller ones, then figure out the smaller problems. Functional programming is more about creating small building blocks and building bigger and better things out of those, and that is just not how I work.

Re: Imperative vs. Functional programming

Posted: Fri Sep 10, 2021 10:22 am
by eekee
I had a friend who said Haskell was good for some things, but there were some tasks which would be a dozen lines of code in Haskell but only a small one-liner in C. I took that as a reason to appreciate impure functional languages.

Re: Imperative vs. Functional programming

Posted: Tue Sep 14, 2021 8:21 am
by AndrewAPrice
The right tool for the task. For example:

Functional programming is great for calculation tasks that produce an answer. Think spreadsheets.

Imperative programming is great for tasks that have a sequence of steps to go through. Think the network code in web browsers.

It's more so a programming style, although languages catering to a particular style make it easier. Haskell has monards. You could adopt a functional style in C++. No global state, mutate no input parameters, pass around functions, etc. But, it can be awkward compared to a language that makes this more natural.

Use the right tool for the task, which might mean mixing them.

e.g. You could build a video game with the main mechanics in an imperative language, but then use a functional language for specific tasks such as determining the damage level if one character attacks another. If you do the latter in a scripting language, it makes it easier to support modding (fans can create new characters or weapons and customize their damage level.)

Re: Imperative vs. Functional programming

Posted: Tue Sep 14, 2021 8:50 am
by Solar
bloodline wrote:Very few languages will ever be as beautiful as C. :)
Well, virtually every non-trivial C program will come with a Makefile to build it.

And Makefile syntax is functional. ;-)

I never could wrap my head around functional-only languages, so the pandora's box that is LISP and its derivatives remains closed to me. But I sure liked those places where functional concepts made my life easier in C++ -- another reason why I like that language so much, being a hodgepodge of whatever-works-best-right-now without shoving some paradigm down your throat. ;-)

Re: Imperative vs. Functional programming

Posted: Tue Sep 14, 2021 9:58 am
by eekee
Solar wrote:But I sure liked those places where functional concepts made my life easier in C++ -- another reason why I like that language so much, being a hodgepodge of whatever-works-best-right-now without shoving some paradigm down your throat. ;-)
When you put it that way, I think I'd really like C++. :D But Forth is a similar kind of hodgepodge, so I'm all right there.

Can you make domain-specific languages (DSLs) in C++ using operator overloading? Or rather, I guess you can, but is it practical? I guess "cout << ..." might count as a DSL. I ask because that's the nearest thing I can think of to the fairly common Forth practice of defining DSLs as temporary language extensions. For instance, I once saw a printf-like system where <% added definitions like %s or %d , and %> restored the dictionary to its previous state.

On another note, I sometimes think I'd like an imperative Lisp.

Re: Imperative vs. Functional programming

Posted: Tue Sep 14, 2021 12:43 pm
by nullplan
eekee wrote:Can you make domain-specific languages (DSLs) in C++ using operator overloading? Or rather, I guess you can, but is it practical? I guess "cout << ..." might count as a DSL. I ask because that's the nearest thing I can think of to the fairly common Forth practice of defining DSLs as temporary language extensions. For instance, I once saw a printf-like system where <% added definitions like %s or %d , and %> restored the dictionary to its previous state.
You can, but operator overloading with different meanings comes at the drawback that you still get the old operator in its intended meaning, even if it does something else now. For example, you correctly point out that the shift operator was overloaded so it can be used with an iostream and whatever other data you want. The drawback is that it is still the shift operator, so it gets parsed as the shift operator. If you look at a precedence chart for C (C++ has basically the same one), you will see that shift is pretty much in the middle. If you want to use expressions that utilize lower precedence operators, you must employ parentheses, or else suffer through very obtuse error messages from the compiler.

That is not to say that this style of overloading is totally without merit, else it wouldn't have stuck around for so long. Operator overloading allows you to define overloads as member functions or as free functions and invoke them with the same syntax. For example, a common way iostreams gets extended with the capacity to print a new type is just by defining a new free function

Code: Select all

std::iostream &operator<<(std::iostream &str, const MyType &foo);
And then you can output a MyType into a stream just like you would anything else. It is not possible in C++ to just add a member function in this way, so if they had used a member function for formatted output, it would not have been possible to extend iostreams in this way.

Code: Select all

cout.write(some_int).write(my_foo).write(std::endl); /* error: no overload for write(MyType&) in std::ostream */
And free functions would just have gotten annoying:

Code: Select all

write(write(write(cout, some_int), my_foo), std::endl);
It is also not possible in C++ to add new operators into the language. If you want that, use Haskell.

Re: Imperative vs. Functional programming

Posted: Sun Sep 19, 2021 2:31 pm
by Seasoft
I heard that functional is suggested as one tool to improve one's programming skill.

Re: Imperative vs. Functional programming

Posted: Sun Sep 19, 2021 3:17 pm
by BigBuda
nullplan wrote:It is also not possible in C++ to add new operators into the language. If you want that, use Haskell.
That (adding new operators), custom attributes (like in C#) and syntactic sugar for properties in classes (instead of get_*/set_*) are the three things that I really think C++ is missing... (but that's just me, others will have different requirements). Instead, they've been adding a lot of stuff for niche cases... sad life.

Re: Imperative vs. Functional programming

Posted: Mon Sep 20, 2021 11:53 am
by Schol-R-LEA
Solar wrote: I never could wrap my head around functional-only languages, so the pandora's box that is LISP and its derivatives remains closed to me.
One thing to note about Lisp - at least most major Lisps such as Common Lisp and Scheme - is that they aren't purely functional. Older classic LISPs predate the formulation of FP as a discipline, and in fact FP (and logic programming, constraint programming, and dataflow programming) was largely developed as a paradigm through DSLs which were developed in LISP 1.5 and it's immediate descendants.

Both Common Lisp and Scheme are multi-paradigm, having assignment forms such as SETF/set!, and are fundamentally more procedural than functional per se; functional programming in those two languages is a style rather than a language feature (though Scheme in particular strongly favors FP). Both also encourage developing DSLs as a means of extending the language in various ways.

By contrast, Clojure is mostly functional, but is designed to easily work with the underlying Java class libraries and can define its own classes as well.

CL in particular having a significant OOP subset called CLOS - though CLOS works very differently from most OO languages. Much of the focus in CLOS is more along the lines of generic programming than OO in the conventional sense, and the class definition approach is both flexible and esoteric. There's an entire textbook on how CLOS is implemented, titled The Art of the Metaobject Protocol, and that title alone will give you some sense of the attitudes of the implementors.

Note that the majority of CLOS is implemented in Common Lisp itself, using macros and read-macros, rather than as part of the underlying compiler (CL is always compiled; even the REPL is compile-and-go, rather than interpreted). It is a library and set of conventions, rather than a part of the language as such.

There are equally complete libraries/DSLs for logic programming, relational programming (both using SQL and using a more Lispy DSL), aspect-oriented programming, constraint programming, dataflow programming, finite automata and regexes in various flavors, pretty much whatever paradigm you can name. While most of these do use the s-expression syntax of the underlying Lisp, the use of macros and/or mini-interpreters mean that pretty much any syntax can be implemented in Lisp, as well.

Scheme doesn't have any official OO support in the language or the standard library, but since much of the language is built around both closures and macros it is trivial to develop an OOP library for it, and many, many different ones exist. These can have very different styles and flavors to them, with some following CLOS's model and other using a model closer to a conventional OO model. This diversity is deliberate, since Scheme is mostly meant for both teaching and research - developing (or at least studying the implementation of) a rump OOP library is a common mid-level project for courses using Scheme as a way of showing off the language's flexibility. A simple one doesn't even need macros, just closures, though most use macros to make the syntax more accessible.

That having been said, if Lisp isn't your thing, that's no problem. It looks and feels very different from other languages and not everyone will like it.

Re: Imperative vs. Functional programming

Posted: Sun Sep 26, 2021 3:54 pm
by h0bby1
From my understanding, functional langage are more derived from lambda calculus, aka stateless, as you dont have to really mannage states, only constants and chains of operations that lead to new value. Which has a side to be easier to mannage for the mind, can parrallelize for free ( no mutable state no problem ). No side effects, no needs for pointers etc and remove lot of hardware architecture details from the algorithm.

It has more a grounding in classic mathematics it can have type system more based on mathematic type theory like abstract algebra etc that is cleaner than things like c++ generics.

If your mind is confortable with mathematics notation, set theories etc you might find yourself more confortable using functional languages, and find OOP is more messy.

For an OS i think you are screwed if you want to stick to functional purity because hardware has states and you have to mannage them, as well as pointers to address those hardware states. But maybe there are techniques to do this using pure functional style.

They are supposed to more oriented towards computation/mathematics/algebra etc

Even pointers dont have a clear algebra.

The bad side is it tend to use more memory and more cpu ressources.

Re: Imperative vs. Functional programming

Posted: Sun Sep 26, 2021 9:06 pm
by Ethin
I really like how Rust does it. Not only is its macro system awesome (you can get pretty wild with the macro syntax, and people have even written parser grammar languages using the macro system, but you can use functional and imperative styles when you like. Both will compile to the same code. For instance, this:

Code: Select all

    let region_range: MiniVec<Range<u64>> = MMAP
        .get()
        .unwrap()
        .iter()
        .filter(|r| r.kind == MemoryRegionKind::Usable)
        .map(|r| r.start..r.end)
        .collect();
is identical to this (more verbose) equivalent:

Code: Select all

    let region_range: MiniVec<Range<u64>> = MiniVec::new();
    for r in MMAP.get().unwrap().iter() {
        if r.kind == MemoryRegionKind::Usable {
            region_range.push(r.start .. r.end);
        } else {
            continue;
        }
    }
Granted, using a purely functional style you lose break/continue, and so there are some places in my code where I've used pure loops because I needed them. But the idea behind FP is that you don't need break/continue, and if you do then one of your predicates is wrong, if I understand it right.

Personally, I've never understood haskell. It just doesn't click for me. The syntax looks like it was deliberately designed to confuse people as much as possible so that only mathematical geniuses could actually understand what it is that your actually doing or wanting to do. Plus the fact that *all* functions have to be pure, and if you want to do something impure, you have to do all this extra stuff just so you can. I like how Rust/C++ do it where they give you the tools to go as functional as you want, but they don't go "Oh by the way you have to completely rethink how logic works, and you have to completely redesign your program to fit the way the designers of the language want your program to work. Oh and you need this special type (and possibly even this special syntax) just so you can do anything other than mathematics". Sorry, but I like to be productive, and Haskell would have me constantly overthinking the design of my program, and I'd end up never getting anything done.

Re: Imperative vs. Functional programming

Posted: Mon Sep 27, 2021 2:24 am
by h0bby1
Ethin wrote: Granted, using a purely functional style you lose break/continue, and so there are some places in my code where I've used pure loops because I needed them. But the idea behind FP is that you don't need break/continue, and if you do then one of your predicates is wrong, if I understand it right.
.
The equivalent of loops in FP is recursion , so break is return, continue is deeper recursion , with generally something like "when" clause to have flow control, and tail call to avoid eating the stack.

Or normally you can do away with loops with map/fold/filter kind of construct that are more mathematically sound.

Re: Imperative vs. Functional programming

Posted: Mon Sep 27, 2021 3:44 am
by h0bby1
Ethin wrote:
Personally, I've never understood haskell. It just doesn't click for me. The syntax looks like it was deliberately designed to confuse people as much as possible so that only mathematical geniuses could actually understand what it is that your actually doing or wanting to do. Plus the fact that *all* functions have to be pure, and if you want to do something impure, you have to do all this extra stuff just so you can. I like how Rust/C++ do it where they give you the tools to go as functional as you want, but they don't go "Oh by the way you have to completely rethink how logic works, and you have to completely redesign your program to fit the way the designers of the language want your program to work. Oh and you need this special type (and possibly even this special syntax) just so you can do anything other than mathematics". Sorry, but I like to be productive, and Haskell would have me constantly overthinking the design of my program, and I'd end up never getting anything done.
Well it's the problem with FP is that its all good if you stick to purely computation. So you will rarely find a language that really stick to FP to a T because all you can do is making computation from input constant.

If you want streams , you cant because they have states.

The good approach is maybe functional reactive programming and coroutine, because they allow to have the minimum in imperative style to mannage state, and then functional style to mannage side effects from those state changes.

The good thing with FP and asynchronous code is that it leave no room for race conditions, can easily be lockless etc.

So it still make life easier for asynchronous code, it favorise referential transparency etc which is always a good thing to have callback mechanism, event handlers and all this kind of things.

But any functional language who want to be somehow competetive in the industry has to add some quirks because sometime you cant do away with states ( UI, streams etc ). Or it would lead to massive performance loss and memory use if you need to create a new copy of everything each time something affect a state.

But states and side effects is always a pita especially in asynchronous/concurent/parralell kind of programming because they lead to race conditions, so all together its never a bad thing to avoid them.

Its make program more predictible with referential transparency etc