> The unifying aspect of new languages such as Rust, Nim, and Gleam is that they were designed from the beginning to be beyond paradigms.
I really don’t think this is correct at all. Rather, Rust/Nim/Gleam are first and foremost imperative languages. They may have some functional and Lispy features thrown in, but that doesn’t change the fact that programs in those languages involve writing statements to be executed one after another — the defining aspect of imperative languages.
If you really wanted to, I guess you could define this particular combination of ‘imperative+functional+macros’ as its own new paradigm. These languages are consistent enough with their design that that might actually make sense. But it’s certainly not ‘post-paradigm‘ in any meaningful way.
Agreeing and amplifying: I believe multi-paradigm is a useful term, but you can always find a prioritization in the paradigms. Your language is going to privilege either mutable or immutable data. It can support both, but one is going to be considered the default. Even if the language itself doesn't, the standard library and the resulting influence it has on the 3rd party libraries will result in a preference. Your language will privilege one side or the other of the expression problem. Your language will privilege statements or functions. Your language will privilege static or dynamic types. Your language will prioritize compile time things or run time things. And so on for quite a few things. Even when someone finds an interesting way to split the difference in one of those categories, that does not defy this categorization, it adds a new one, a new way of prioritizing. But that new way still won't be a completely even 50% split.
There are many multiparadigm languages. They are even the norm now. But being multiparadigm doesn't mean they all support all paradigms equally. Programming X in Y is a problem for almost all combinations of X and Y for X != Y, because the language will always have a "grain" to it. Thus, it is still meaningful to argue about which paradigm preference is suitable to which tasks.
Even two of the most similar languages there are, at least in terms of language spec, Python and Ruby, demonstrate significant differences in the orientation of the library ecosystem in some of their philosophies.
To add to my parent comment, I think there’s another point to be made here: ‘post-paradigm’ is, to some extent, a contradiction in terms. You can’t build a language without its basic structure implying some paradigm (or possibly more than one).
There’s a perspective I find useful here. I tend to think of different ‘programming paradigms’ as different approaches to solving problems. In imperative languages, you solve problems by modifying values in sequence until you get to the answer; in functional languages, you solve problems by building up a function which gives you back the answer; and so on.
The key thing here is, you do need to give yourself some way of solving problems. That translates directly to the paradigm which your programming language adopts. If you give yourself more than one way of solving problems, then the language becomes multi-paradigm. In rare cases, you might even end up inventing a totally novel problem-solving approach, and hence a new paradigm… but even that’s not ‘post-paradigm’, it’s just another paradigm.
Gleam is one of the really really functional languages out there. There is no mutability, there are no statements, no loops. It has let bindings, function application, and conditionals through if/case, and that’s it. It has just tricked you because it has a very nice and friendly syntax.
It also has no macros so I don’t know what you mean in that last paragraph.
I suspect it is possible to make the same argument for the contrary position. Once we're talking about "some functional and Lispy features thrown in"; we must start to question what a paradigm is.
If I write a program, fundamentally I have a blob in my head that I'm reifying into formal logic. It doesn't make sense to talk about the blob as having a paradigm; but I'm not sure that it is useful to talk about the reification as having a "paradigm" either. The appropriate techniques to be used are on a functional-imperative spectrum based on how stateful the problem is.
This whole idea of programming paradigms I think is a mis-take of a more fundamental question of how to classify programming problems - we're looking at the shadow in Plato's cave and getting nonsense because we expect the problem to to take on aspects of the programming language. Which is not a strategy for achieving success. We should be classifying problems based on state, not programming languages based on paradigms.
Most of the experts have figured that out, they pick their programming language based on the problem space they want to deal in. But the paradigm paradigm doesn't help in making those decisions, so it's utility is low.
I disagree. In Rust, traits are used all over for dynamic dispatch, the defining feature of object-oriented programming. Moreover, all three languages support structural pattern matching (borrowed from functional programming) as a core control-structure.
Certainly all three languages can be used in a simple, imperative style. But that's not the only paradigm that can be used unlike in C or early versions of Python. Many programs in these languages look significantly different than just statements and procedures.
Yeah, I'm having trouble seeing how Rust/Nim/Gleam can be written in a logic programming style (like Prolog or Datalog).
At minimum, that means there are _two_ paradigms: logic programming and "beyond paradigms"....which sorta means that we're not really beyond paradigms now, are we?
I think the reality is that certain previously-niche paradigms became cool again, and folks started grabbing off some of the most-visible pieces of those paradigms (pattern-matching, ADTs, map/reduce/filter, maybe even a pipeline operator) and adapting them to other paradigms.
The closest thing I've seen to truly multi-paradigm was a programming language now lost to time called Metamine, which I kept a clone of[1]. Here's some previous discussion[2]
In Metamine
a := b is a normal assignment
c = d+1 means that c will ALWAYS be equal to d+1
z = 10-time results in a countdown timer, z
That magical equals is declarative programming... something that I've only seen mixed with imperative functioning that one time.
IIRC, this was called "permanent assignment" in CPL, a name I very much like.
It's also pretty much the same as a dataflow constraint (see: Amulet, Garnet, Spreadsheets, ...)
In Objective-S, I use the syntax |= for the unidirectional variant of a dataflow constraint, =|= for bidirectional (ObjS uses := or ← for assignment, = for equality). So the above would be:
a := b.
a ← b.
c |= d+1.
z |= 10-time. (if 'time' were the current time in ObjS)
'Multi-paradigm' languages are quite old, like Lisp.
Got closures? Then you've got objects.
Can you write code that's executed sequentially? Then you've got imperative programming.
Can you pass a function as a parameter to another? That's pretty functional.
Having this in a language has been common for decades. But there are more paradigms, notably 'macro-oriented' programming and logic programming. Are these well supported in Rust and Nim? If not, then they aren't as "beyond paradigms" as Lisp.
There's arguably several forms of object oriented languages too, besides what might be called Java/C++/Python style there's message passing Smalltalk style and prototype style as in JavaScript and its parent. Would probably need to support these styles too, to be "beyond paradigms".
Assembler could also be considered a programming paradigm, so we'd need to support that too.
And if logic programming is a paradigm, constraint programming likely is another. Glue or shell programming yet another.
I think a lot if the paradigm frame comes from programming being still relatively new (although that's becoming a less and less viable meme). We're still very "one true way" in how we talk about software design.
Personally, I'd love to see us talking more in terms of problems/solutions.
To give an example. State leads to complexity and bugs, and it can be minimized by preferring pure functions where possible. That's a good principle that can be learnt from without embracing everything functional and rejecting everything that involves objects.
A better example is the Oz programming language and the Mozart programming system (https://en.wikipedia.org/wiki/Oz_(programming_language)) explained in the book Concepts, Techniques, and Models of Computer Programing by Peter Van Roy and Seif Haridi.
Not necessarily. Oz was created as poster child to multi-paradigm language design. The book shows this. Each paradigm gets its own chapter and Oz examples to program in each are shown. This is similar to the cirricula structure author mentions. In contrast the article makes a case for programming without paradigm distinction and mixing elements across styles.
Since Oz's Wikipedia page was linked, Wikipedia apparently has a page (https://en.wikipedia.org/wiki/Comparison_of_multi-paradigm_p...) comparing multi-paradigm languages (though can be argued all languages nowadays are multi-paradigm). A summary table for some of those (partial support isn't considered):
Interesting ones will be Wolfram supporting the most basic (not in others) natively, CLisp the only one supporting all the basic considering libraries, and Julia that alongside CLisp support the most considering extra (in others). Moreover CLisp alongside C++ show that thanks to libraries supported can be greatly extended (doubled in those two). To also compare to article, another will be Haskell supporting more paradigms (even only considering native ones) than Rust. Sadly Nim and Gleam aren't in list.
This has been true of Common Lisp almost since the beginning. Supported functional, imperative and object oriented paradigms out of the box. And macros allow supporting almost any other programming style in the language as well. Probably any programming paradigm you can think of at some point was added to Common Lisp as a library through macros.
From the content of the article it is not clear if the author really knows about the topic of programming paradigms (as per undergraduate courses).
As other commenters are saying, in 2024 we can combine paradigms more than before the 2000s but paradigms continue to exist. It is very different to use think in functional terms than in imperative ones or even in purely logic terms as in Z3. There are combinations that are pretty natural (e.g. LINQ in .NET) while others go beyond specific languages: just interfacing components written under different paradigms.
My two cents is that programming languages will always favor a paradigm over others because many paradigms are strongly connected to the compiler or interpreter and offer syntax sugar to give the developer different strategies. The multiparadigm approach would much alike the lines of Microsoft .NET (F#, C#) where specific programming languages can use a unified framework.
In futuristic terms I think the whole programming field will majorly lend more toward reuse and developing based on specs than what we are doing now: reinventing the wheel across different organizations. For example, front-end development should be more visual and parametric than the code it requires to write.
"Think" being the operative word. Paradigms are mental models of computation and organization. The benefit of designing a language around a single model is ease of understanding. The downside is that this locks the developer into a single way of looking at things, which may not always be the best match for the domain. Multi-paradigm approaches (most modern langs) broaden the available options, but at the cost of greater cognitive load.
As the big name languages become a never-ending accretion of multi-paradigm features, then it just feels like a sort of Grey Goo landscape. There's a charm in things remaining true to themselves, even at the cost of maximum utility.
Paradigms aren’t just technical capabilities within a language, they’re also modelling approaches for real world problems.
Imperative programming lets you think about a series of steps. Structured programming lets you split and name series of steps into known procedures and structures. Object oriented programming (and object relational mapping) was wildly successful because a lot of enterprise programming is about interactions between durable real world entities. Functional programming remains somewhat niche because modelling in terms of pipelines of pure functions is hard to map to real world problems without great discipline.
None of these is right or wrong, nor is any subset or combination. But they’re not just regrettable constraints, they’re valuable ways of thinking. Any language seeking to grow beyond one or more paradigms still needs to offer a clear and consistent way for programmers to reason about the world.
I more or less agree with the author that "programming paradigms are becoming practically the same as programming styles", but even so, some languages have core features that cannot be replicated by mainstream "multi-paradigm" languages, and then that I can call them as the Next Paradigm.
An example is dependent types. This is impossible in all the languages the author mentions in the article (yes, well, GHC Haskell comes close), but there is at least one "21st century general-purpose language" that uses it, called Idris.
I think this article is _closer_ to right than a lot of writing on programming paradigms is, but still misses a central idea.
Programming paradigms can't be defined intensionally, by listing their features, nor extensionally, by listing programming languages that fit each paradigm. Either way results in unsatisfactory definitions from which reasonable people will identify errors of excluded languages.
This is because programming paradigms aren't sets, they're cognitive categories. Programming paradigms are subjective mappings of conceptual framings of program structure onto specific languages. A language fits a paradigm if that mapping is subjectively natural.
Of course, people tend not to like subjective definitions, but this is more accurate.
Hmm...I still don't think that the differences between imperative, OO and functional programming are sufficient for them to be called "paradigms" and for a language that supports variations to be called "multi-paradigm"
bradrn|1 year ago
I really don’t think this is correct at all. Rather, Rust/Nim/Gleam are first and foremost imperative languages. They may have some functional and Lispy features thrown in, but that doesn’t change the fact that programs in those languages involve writing statements to be executed one after another — the defining aspect of imperative languages.
If you really wanted to, I guess you could define this particular combination of ‘imperative+functional+macros’ as its own new paradigm. These languages are consistent enough with their design that that might actually make sense. But it’s certainly not ‘post-paradigm‘ in any meaningful way.
jerf|1 year ago
There are many multiparadigm languages. They are even the norm now. But being multiparadigm doesn't mean they all support all paradigms equally. Programming X in Y is a problem for almost all combinations of X and Y for X != Y, because the language will always have a "grain" to it. Thus, it is still meaningful to argue about which paradigm preference is suitable to which tasks.
Even two of the most similar languages there are, at least in terms of language spec, Python and Ruby, demonstrate significant differences in the orientation of the library ecosystem in some of their philosophies.
bradrn|1 year ago
There’s a perspective I find useful here. I tend to think of different ‘programming paradigms’ as different approaches to solving problems. In imperative languages, you solve problems by modifying values in sequence until you get to the answer; in functional languages, you solve problems by building up a function which gives you back the answer; and so on.
The key thing here is, you do need to give yourself some way of solving problems. That translates directly to the paradigm which your programming language adopts. If you give yourself more than one way of solving problems, then the language becomes multi-paradigm. In rare cases, you might even end up inventing a totally novel problem-solving approach, and hence a new paradigm… but even that’s not ‘post-paradigm’, it’s just another paradigm.
fmbb|1 year ago
Gleam is one of the really really functional languages out there. There is no mutability, there are no statements, no loops. It has let bindings, function application, and conditionals through if/case, and that’s it. It has just tricked you because it has a very nice and friendly syntax.
It also has no macros so I don’t know what you mean in that last paragraph.
roenxi|1 year ago
If I write a program, fundamentally I have a blob in my head that I'm reifying into formal logic. It doesn't make sense to talk about the blob as having a paradigm; but I'm not sure that it is useful to talk about the reification as having a "paradigm" either. The appropriate techniques to be used are on a functional-imperative spectrum based on how stateful the problem is.
This whole idea of programming paradigms I think is a mis-take of a more fundamental question of how to classify programming problems - we're looking at the shadow in Plato's cave and getting nonsense because we expect the problem to to take on aspects of the programming language. Which is not a strategy for achieving success. We should be classifying problems based on state, not programming languages based on paradigms.
Most of the experts have figured that out, they pick their programming language based on the problem space they want to deal in. But the paradigm paradigm doesn't help in making those decisions, so it's utility is low.
hydroxideOH-|1 year ago
Certainly all three languages can be used in a simple, imperative style. But that's not the only paradigm that can be used unlike in C or early versions of Python. Many programs in these languages look significantly different than just statements and procedures.
bmitc|1 year ago
ubertaco|1 year ago
At minimum, that means there are _two_ paradigms: logic programming and "beyond paradigms"....which sorta means that we're not really beyond paradigms now, are we?
I think the reality is that certain previously-niche paradigms became cool again, and folks started grabbing off some of the most-visible pieces of those paradigms (pattern-matching, ADTs, map/reduce/filter, maybe even a pipeline operator) and adapting them to other paradigms.
mikewarot|1 year ago
In Metamine
That magical equals is declarative programming... something that I've only seen mixed with imperative functioning that one time.[1] https://github.com/mikewarot/metamine
[2] https://news.ycombinator.com/item?id=27555940
mpweiher|1 year ago
It's also pretty much the same as a dataflow constraint (see: Amulet, Garnet, Spreadsheets, ...)
In Objective-S, I use the syntax |= for the unidirectional variant of a dataflow constraint, =|= for bidirectional (ObjS uses := or ← for assignment, = for equality). So the above would be:
https://objective.stlanna|1 year ago
ivanjermakov|1 year ago
cess11|1 year ago
Got closures? Then you've got objects.
Can you write code that's executed sequentially? Then you've got imperative programming.
Can you pass a function as a parameter to another? That's pretty functional.
Having this in a language has been common for decades. But there are more paradigms, notably 'macro-oriented' programming and logic programming. Are these well supported in Rust and Nim? If not, then they aren't as "beyond paradigms" as Lisp.
There's arguably several forms of object oriented languages too, besides what might be called Java/C++/Python style there's message passing Smalltalk style and prototype style as in JavaScript and its parent. Would probably need to support these styles too, to be "beyond paradigms".
Assembler could also be considered a programming paradigm, so we'd need to support that too.
And if logic programming is a paradigm, constraint programming likely is another. Glue or shell programming yet another.
And so on and so on.
benrutter|1 year ago
Personally, I'd love to see us talking more in terms of problems/solutions.
To give an example. State leads to complexity and bugs, and it can be minimized by preferring pure functions where possible. That's a good principle that can be learnt from without embracing everything functional and rejecting everything that involves objects.
ergonaught|1 year ago
Greenspun’s Tenth Rule always irritated me more than it amused me but here we are.
LettuceSand12|1 year ago
rramadass|1 year ago
forgotpwd16|1 year ago
Since Oz's Wikipedia page was linked, Wikipedia apparently has a page (https://en.wikipedia.org/wiki/Comparison_of_multi-paradigm_p...) comparing multi-paradigm languages (though can be argued all languages nowadays are multi-paradigm). A summary table for some of those (partial support isn't considered):
Interesting ones will be Wolfram supporting the most basic (not in others) natively, CLisp the only one supporting all the basic considering libraries, and Julia that alongside CLisp support the most considering extra (in others). Moreover CLisp alongside C++ show that thanks to libraries supported can be greatly extended (doubled in those two). To also compare to article, another will be Haskell supporting more paradigms (even only considering native ones) than Rust. Sadly Nim and Gleam aren't in list.jimbokun|1 year ago
wslh|1 year ago
As other commenters are saying, in 2024 we can combine paradigms more than before the 2000s but paradigms continue to exist. It is very different to use think in functional terms than in imperative ones or even in purely logic terms as in Z3. There are combinations that are pretty natural (e.g. LINQ in .NET) while others go beyond specific languages: just interfacing components written under different paradigms.
My two cents is that programming languages will always favor a paradigm over others because many paradigms are strongly connected to the compiler or interpreter and offer syntax sugar to give the developer different strategies. The multiparadigm approach would much alike the lines of Microsoft .NET (F#, C#) where specific programming languages can use a unified framework.
In futuristic terms I think the whole programming field will majorly lend more toward reuse and developing based on specs than what we are doing now: reinventing the wheel across different organizations. For example, front-end development should be more visual and parametric than the code it requires to write.
mtVessel|1 year ago
frou_dh|1 year ago
PartiallyTyped|1 year ago
thom|1 year ago
Imperative programming lets you think about a series of steps. Structured programming lets you split and name series of steps into known procedures and structures. Object oriented programming (and object relational mapping) was wildly successful because a lot of enterprise programming is about interactions between durable real world entities. Functional programming remains somewhat niche because modelling in terms of pipelines of pure functions is hard to map to real world problems without great discipline.
None of these is right or wrong, nor is any subset or combination. But they’re not just regrettable constraints, they’re valuable ways of thinking. Any language seeking to grow beyond one or more paradigms still needs to offer a clear and consistent way for programmers to reason about the world.
refactor_master|1 year ago
Just take a look at how Python is evolving, and the trail of essentially “dead” features and standards it’s leaving behind.
bashauma|1 year ago
An example is dependent types. This is impossible in all the languages the author mentions in the article (yes, well, GHC Haskell comes close), but there is at least one "21st century general-purpose language" that uses it, called Idris.
alilleybrinker|1 year ago
Programming paradigms can't be defined intensionally, by listing their features, nor extensionally, by listing programming languages that fit each paradigm. Either way results in unsatisfactory definitions from which reasonable people will identify errors of excluded languages.
This is because programming paradigms aren't sets, they're cognitive categories. Programming paradigms are subjective mappings of conceptual framings of program structure onto specific languages. A language fits a paradigm if that mapping is subjectively natural.
Of course, people tend not to like subjective definitions, but this is more accurate.
aryehof|1 year ago
A better viewpoint is to question what sort of problems or way to model a system, is a particular paradigm best suited to?
unknown|1 year ago
[deleted]
unknown|1 year ago
[deleted]
mpweiher|1 year ago
"What kinds of music do you have here"
"Oh we got both kinds: Country and Western"
(Blues Brothers, https://www.youtube.com/watch?v=vS-zEH8YmiM)
Let's see:
OK, that's a little facetious, but only a little. More details here:https://2020.programming-conference.org/details/salon-2020-p...
So yeah, we need to go beyond this.
https://blog.metaobject.com/2019/02/why-architecture-oriente...
bilvar|1 year ago
tristramb|1 year ago
lemper|1 year ago