I'd love to see an updated version of this. After reading the stories from the Rust/Servo/Stylo developers, it feels like Rust might just be pushing both "fancy type systems" and "parallelism" to the left.
Also, if you count GPU programming under "parallelism" then it's gotta be a huge YES.
He mentions Rust in the garbage collection category, so it's interesting that it's not mentioned in the fancy type category. Maybe he considers higher kinded types a requirement to be fancy, which is still just an RFC in Rust.
I agree on parallelism. I came to the conclusion that the author must not be including GPU programming in his assessment which does seem odd given how important it has been in recent years.
I think Swift has a lot of developers adopting fancy (or fancier) type systems and functional programming concepts, even if they don't realized that's what they are doing.
If you leave off immutability, Javascript, C++, and even Java 8 have introduced first class functions as mainstream programming concepts.
I'm confused as to why he doesn't put functional programming as a yes. He writes "Functional languages are still quite niche, but functional programming ideas are now mainstream, at least for the HN/reddit/twitter crowd."
While purely Functional languages are definitely not mainstream, as he puts functional programming ideas are pretty mainstream. At the same time major OO languages like java have incorporated functional programming ideas, so arguably even Java is not purely Object Oriented anymore. It seems to me by his criteria that would also put OO as a no too.
If he comes from OO languages I think this is a bias because it is easy to take OO for granted and put strict requirements on foreign Functional Programming before accepting it as successful. However it seems to me the only criteria that should be needed to call either paradigm successful is if their ideas are are mainstream, which is true for both languages.
Basically if Function Programming ideas have gained currency then it should be regarded as successful.
JS is multi-paradigm, it's functional but it's also 3 other things that muddy the water a bit.
Especially considering most programming languages have those neat helper methods or stdlib implementations that basically bring functional programming without changing the language much.
JS may be capable of a pure functional programming style, but from 20 years of observing it's use (and misuse), functional JS is an exceptionally rare occurrence; an edge case.
Javascript may have some functional concepts (mainly, functions as first order objects) but the programming style of most common javascript projects is not functional. This is with the notable exception of event-driven frameworks and precompiled languages like purescript.
Well for comparison, GC was a yes right. And basically every popular (modern) language incorporates garbage collection. Functional programming, or at least fairly strict functional programming, still hasn't really caught on. Of the juggernaut languages, C/C++, python, Ruby, Java, JavaScript none are truly functional (I don't use JavaScript but the code I have seen in it doesn't often look functional). Until something like Scala cracks the top 5 I agree with calling it a maybe.
JavaScript and Ruby are functional too. Scala supports other paradigms than FP too. They are all multi-paradigm. The difference is that certain programming styles might be more natural in some languages than in others.
Well, the first listed paradigm for Scala on wikipedia is functional, JavaScript and Ruby both have OO followed by imperative. And anyways supporting functional programming and being designed for it are not the same thing. Yeah, I can right functional Ruby, but that isn't going to be by initial inclination when writing a Ruby script. It would be for Scala.
Just one thing: when you write that Ruby script, could one of the reasons why you don't use a FP style be not only that maybe it wouldn't be natural to do so in Ruby, but also that it's unsuitable for the kind of problem you are trying to solve with that script to begin with?
I mention this, because I have the impression that people tend to believe that to solve a programming problem you should use whatever paradigm is perceived as the main one for the language at hand. However, I believe that it's the problem that should dictate the paradigm.
I agree in principle, but rather than the problem dictating the paradigm, I would say it usually dictates the language. If a problem is well suited to a functional implementation then I'll probably break out Scala to solve it.
But the thing is, what if you are stuck with a given language, and/or its a biggish complex project where different aspects are better solved with different paradigms?
I don't think there's any one knock-down criterion, but there are several small things that add up:
-Scala was intended to have strong FP and OO support from day 1
-Scala has very strong support for immutable values and
persistent data structures. It's hard to do FP efficiently without these
-Similarly, Scala has built in support for laziness to a significantly greater extent than most languages. This is arguably important because it supports immutability, there are some important mutable algorithms that have no efficient immutable equivalent without laziness
-Strong lambdas (unlike, e.g., Python)
-Many of the major Scala libraries are either written in a heavily functional style or support highly functional APIs, while libraries in most languages do not
Not a standard term – I'm just referring to the ability to do anything in a lambda that you can do in the body of a function, such as defining intermediate values, which is not possible in Python.
I think this is nitpicking. In python you can do everything you want in inner functions, they just have to be named. Additionaly there is simple syntax for single expressions, that don't need names. Lack of TCO is a lot bigger obstacle to using more functional style
Also interesting in addition to the other fine replies is that Javascript qua Javascript hasn't actually moved all that much in the past 15 years, and in 2002 JS would definitely not have been a "functional language".
I'd say it's a language whose issues are sometimes something that FP is best at papering over, but as an FP language, it is quite lacking if you're used to something like Haskell, Erlang, or Lisp. I actually put it in the category of OO-FP languages, languages that have a lot of the FP constructs (especially from when Lisp was the epitome of FP) but are primarily object-oriented languages. It's a pretty decent paradigm, but it really ought to be distinguished from FP languages where there are no OO features in them at all, or much more rarely, where they are clearly second-class.
JS had first class functions from the beginning, which I think is one of the major things necessary for FP. Compare that with a language like Java, which did not, and I think still doesn't (lambda's aren't quite the same).
JS doesn't really support traditional inheritance either, so describing it as OO seems odd to me.
I consider anything that binds data to methods and has a concept of "data.method()" to be OO. In the OO religion I'm an ecumenicist.
And even within my ecumenicalism, I consider inheritance in the strictly C++/Java sense of relatively little importance, and dropping. Rather than being essential, it turns out to have been accidental, and also arguably a mistake, even on purely OO grounds.
That's a silly distinction. It's also wrong. Rust 'binds data to methods and has a concept of "data.method()"' and is not OO by any meaningful definition. It's simply sugar for Trait::method(&data).
Java has been multi-paradigm since the beginning, although it favours a stateful style for sure.
FP is by no means restricted to purely functional languages. My impression is that the ideal approach is to use the paradigm most suitable for the problem/component at hand (principle of least expressivity), so I prefer multi-paradigm languages over pure ones, although of course I understand that there are domains where one can benefit from the optimizations made possible by purity.
Understanding how to do this requires much more of a learning effort, learning more concepts, techniques and idioms, which I suspect is why FP is still lagging; I don't believe it is for any fundamental reason.
The other thing is that there are many more programming paradigms than just functional and stateful.
Not to mention, these languages actually work for many, many domains. A shit-load of C# could just as well be F#. In fact, lots and lots of people do use F#/Scala/OCaml/etc. to build real systems.
Just because something isn't "the most popular" doesn't mean that thing doesn't work.
I think it's important to make the distinction between a successful idea and a good one. For example OO as a paradigm in mainstream languages (C++, Java) has been very successful, despite it being more often than not a bad idea (e.g. horrible inheritance hierarchies are still implemented in this day and age, with dire consequences on code quality).
In OP's article, OO is filed under "what works", which I strongly disagree with. If anything, software development works DESPITE OO, which in my experience constantly hinders progress because of rigid architectures.
I don't believe that the problem is OO in itself, but the way in which it is often used. You can write a bad program in any paradigm, and a good one too.
FP is less popular and tends to attract a more curious crowd, who is more willing to learn how to use it well, whereas OO languages are used by everyone.
On top of that, OO is build on top of a more expressive computation model, the stateful one, which because of its power is much more difficult to use well (and easier to abuse) than the much simpler functional/declarative model.
> I don't believe that the problem is OO in itself, but the way in which it is often used.
That's similar to what proponents of communism have been saying - "it does work if you do it right". The problem is that things start breaking down as soon as the project scale. For small programs a pure OO model can work, but increased complexity means people will definitely switch to a hybrid OO-(procedural|functional) style, simply because pure OO is untenable in large codebases.
Haha, communism. Communism failed in Russia. But democracy failed in Russia too. Was communism the problem? I am half kidding, but I have wondered sometimes ...
As much as FP has made my life easier, have to disagree with you on OO. Any language/paradigm is capable of producing bad code. In my first job a high up manager brought in Clojure to a department filled with Java and OO acolytes. While the language was amazing, the Clojure code base was filled with gigantic let statements simulating imperative code, functional spaghetti, and given the lack of a good IDE difficult to debug (had to throw exceptions just to see variable values... shudders). The point is not that FP is bad, just that any tool in unskilled hands can produce bad code.
Not sure what it is like for the industry at large, but from what I've seen a dominant paradigm in Java is to separate out model classes that are basically just structs with Service or Workflow classes that manipulate the data. It's questionable how much of that is still OO (at least when I started learning it the narrative was to put your code where your data is. POJOs are the opposite of that). Given say having a high level service that calls low level services and external system while returning a result produces code thats very easy to trace and provides solid abstraction to the calling code. Also if you've read Uncle Bob's data structure vs. Object dichotomy you'll see how Objects are objectively better in some scenarios, and OO languages give you powerful tools for objects.
That said 100% agree with you on horrible inheritance hierarchies. What I think would be best is some course on how to combine OO and FP paradigms to get the best of both worlds (though tbh it'd probably be 90% FP with some OO).
"What I think would be best is some course on how to combine OO and FP paradigms to get the best of both worlds"
If you want to find out, read "Concepts, Techniques, and Models of Computer Programming". It's mindblowing. It answers that question exactly.
This is a dense but exceptionally written 1000 page book, but maybe you can just read section 4.8.5 to get an idea [1]. However, I think you will take more than just reading this bit, to understand the different models (many more than the 2 everybody talks about).
Section 4.8.7 is actually "Using different models together", with the key "impedance matching" concept.
The author sort of summarizes it here [2]
There is also a mooc in edx, but it just scratches the surface of what's in the book [3]
The Java 8 lambda syntax is all objects under the hood, and the Haskell "do" notation is all functional under the hood. It's impressive that both languages are able to accommodate other programming paradigms while remaining pretty much the same under the hood.
"It's impressive that both languages are able to [efficiently/effectively] accommodate other programming paradigms while remaining pretty much the same under the hood."
Lisp languages aren't really growing. The most hyped lisp style language is Clojure and even it isn't growing. Here's a Google trends comparison of Clojure, Clojurescript, List, Racket, and Scheme:
The only functional programming language that is showing any real growth is Scala, but that is also modest compared to the ones that are already much bigger or growing much faster:
Where functional programming is growing is in existing large OO languages. All of them now have lambdas. Most have mature immutable and composable data structure libraries. And other functional style syntaxes like pattern matching are being introduced in many of them.
"other functional style syntaxes like pattern matching are being introduced in many of them"
The Interpreter and its dual the Visitor GOF pattern have made what amounts to pattern matching possible in OO languages for a few decades now [1].
The whole point of these patterns is to write recursive functions following recursive data types, which is one of the main use cases for pattern matching (ok, more generally these are used to break data structures apart).
In particular, if you look at an example of the Visitor pattern, you will see that it has exactly the same structure as a recursive function that separates cases in a FP language [2]
Here is a detailed explanation of how to do it [3]; it is the "little language" technique (which I suspect is the reason why it is called the Interpreter).
I don't understand what is meant by "capabilities". My understanding of what capabilities are is so abstract, that asking if they worked is not something that could possibly be asked. I might have missed something, or this guy is an architecture astronaut (both?).
He's talking about capability security. Look up the Joe-E programming language for a capability secure subset of Java if you want an idea of what sort of properties such a language must have.
In some ways the Android/iOS permissions system is a form of "capabilities". Granularity is a problem: too granular and they're tedious, not granular enough and you end up leaking your contacts to your torch app.
Linux capabilities aren't capabilities in the sense of capability-based security! They don't follow that security model.
It's just an unfortunate pun. Capability-based security wasn't mainstream at the time they were invented. It arguably isn't now either. You can argue that Android/iOS are capability-based, but the model is pretty watered down.
Capability-based security for end users (rather than sys admins) is an unsolved problem as far as I can tell.
I learned to program sometime around 1988 or 89 when I was 12 and have been doing it for 28 years. I saw several of these rise and fall, and conventions have changed greatly even though most of us are still using C-style languages.
The highest leverage I've found comes from spreadsheets and relational databases because they require little or no code to accomplish so much. So I think that declarative or 4th generation programming languages deserve an honorable mention in the "yes" category.
The lowest leverage has been on the object-oriented side, especially with C++. Java is the least abstract language I've used in recent memory, due to its obsession with staying as far from functional programming as it can (closures were accomplished with anonymous objects until version 8!). There is simply no way to infer where a value was set without tracing the entire code, which slows development time by a factor of 10 to 100 over more functional techniques that use methods to derive state instead of values. So I think the "No" category needs a mention of highly imperative code and its tendency to become spaghetti.
The single most damaging practice I encounter daily is the breaking of convention and the loss of programming context that we've built up in our minds over the years. So while most functional programming languages are conceptually brilliant, they stray so far from mainstream languages like Javascript that I think they complicate syntax unnecessarily. Heavy-handed patterns also urge us to segregate code into parts when the logic doesn't require it, which I often find unintuitive. Mobile development especially, with its obsession with delegation, event broadcasting, observers and nondeterministic behavior of partially uninitialized views (especially recycler view and UITableView) feels like always having to remember 10 or 20 digits when we can only comfortably manage 7. Types for the sake of types will likely expand code size and complexity by an order of magnitude when a simple compiler would have accomplished nearly as much. I have low confidence that any of these will survive the next tech bubble.
I view parallelism and AI as a great uncharted sector of computer science that was stifled by Microsoft, Apple, Intel and NVIDIA. Had FPGAs or open source graphics cards taken off after the 90s, we would have a very different view of things like the Actor model (Erlang, Go, etc). So shared threads are a huge "no", but the private address spaces/streams/message passing and copy-on-write model of UNIX is a huge "yes" and we'll likely see these techniques adopted at the language level in the next decade. It would also be nice to have the numerical computing techniques from MATLAB so we can operate on matrices instead of primitives and saturate the hardware with less effort. Under these tools and conventions, AI loses much of its mystery because you realize you can always brute force a solution and evolve more elegant ones later to find a better local optimum.
"closures were accomplished with anonymous objects until version 8!"
Java has had closures through inner classes since the beginning, albeit admittedly in a verbose way. This is a quote from page 540 of "Concepts, Techniques and Models of Computer Programming":
Full lexical scoping. Full lexical scoping means that the language supports procedure values with external references. This allows a class to be defined inside the
scope of a procedure or another class. Both Smalltalk-80 and Java support procedure values (with some restrictions). In Java they are instances of inner classes (i.e., nested classes). They are quite verbose due to the class syntax (see the epigraph at the beginning of this section).
But I think this is already enough to do high order programming, given that it effectively allows having functions as values (and hence high order functions), and support all 4 basic techniques high order programming builds upon: procedural abstraction (which relies on closures), genericity, instantiation and embedding [1].
I have to admit that I am not sure if I understand what you mean by "There is simply no way to infer where a value was set without tracing the entire code, which slows development time by a factor of 10 to 100 over more functional techniques that use methods to derive state instead of values". My (possibly wrong) interpretation is that you are referring to lazy execution, given that this technique associates a variable with a function that creates its value but whose execution is delayed until triggered when the value is actually needed.
Is this correct? If it is, then explicit lazy execution can certainly be accomplished in Java, given that, as I have said before, it allows embedding procedure values in a data structure. Of course, this is not as convenient as implicit lazy execution as in Haskell with its non strict evaluation, but it achieves the main purpose of laziness all the same, which is to optimize resources by allowing consumers rather than producers to drive value creation and hence generate data structures incrementally (as they are needed) rather than eagerly (as in simpler data driven techniques): stream programming; another advantage of laziness is of course purely functional persistent data structures in some cases with good performance ([3] and [4]).
"It would also be nice to have the numerical computing techniques from MATLAB"
I couldn't agree more with this. For instance, if possible, for a ML project I think it's better to do as much research/experiments/development as possible in Matlab/Octave, and then translate it to Python or whatever the production language is (would love to hear opinions on this). It would be so nice if such translation could be avoided (maybe a preprocessor could automate it, but still ...).
I believe that the reason is that Matlab is just a much more natural language for mathematical programming. I did the wonderful mooc [2] in Matlab, and much prefered it compared to the Python solutions I saw.
OK, apologies for making such a long post. Here is my point (which has turned out to be pretty long too):
1) I have realized that systematically learning programming concepts, models and algorithms first, and how to apply them through programming techniques is much more important than just keeping on learning new languages and frameworks. For this, I am finding "Concepts, Techniques and Models of Computer Programming" invaluable; it covers an amazing amount of ground, and has an excellent bibliography to know where to learn more of a particular aspect. It is is a successor of SICP, which is very good too, and, I suspect as a tribute, is the first reference in CTM.
2) Learn how to do lightweight design upfront based only on the problem/requirement independently from language; the book above helps enormously, but I also really like the approach in the 2008 version of the MIT course 6.005 (later versions are watered down IMHO) [1]. It reinforces this design approach, and has, AFAIK, the best approach to using Design Patterns properly and systematically: to bridge the gap between design and code, which this way just flows almost automatically from the design. It may not be immediately obvious, but this course has a lot in common with SICP. For this reason I am highly sceptical of TDD, although I love to write the tests first and incrementally.
3) Once you know 1), many aspects of learning a new language and using it well are a piece of cake, because what you learned in 1) transcends any particular language and is timeless; I am now starting to enjoy mapping what I learned in 1) to different languages.
4) if you have to or want to use a language that is lacking direct support for anything in 1), if the language's computing model allows it (and many do, it is amazing how adding just one little concept to a language opens a whole range of possibilities but also problems, i.e. destructive assignment, threads, exceptions, triggers, ports, dataflow variables, etc), you can just build an abstraction or find a mature library that implements it. It is equally amazing how much you can still accomplish even if you remove one of the those concepts from a language, like destructive assignment, if you know the right techniques. It may not be as efficient and convenient as a built in abstraction, but will very likely still be much better than the alternative of implementing a design that is not the right one for the problem/requirement.
5) there is no need at all to be intimidated by a language or system with an enormous amount of features/libraries. Most of the time you only need to select a subset of the language to accomplish your goal efficiently. From 1) you will learn exactly how to do this and exactly why it is crazy to try to use the full power of a language; you should actually do the exact opposite, use as few concepts of a language as you can get away with while still writing a program that has a good balance of all required good properties.
>" DEC started a project to do dynamic translation from x86 to Alpha; at the time the project started, the projected performance of x86 basically running in emulation on Alpha was substantially better than native x86 on Intel chips."
I'm really curious how an Alpha emulating x86 could be faster than the native x86? Can someone shed some light on how this would be possible
And a bit further in the article: "By the time DEC finished their dynamic translation efforts, x86 in translation was barely faster than native x86 in floating point code, and substantially slower in integer code."
63 comments
[ 4.3 ms ] story [ 112 ms ] threadAlso, if you count GPU programming under "parallelism" then it's gotta be a huge YES.
(though I guess you know that, since you're the one who asked him...)
If you leave off immutability, Javascript, C++, and even Java 8 have introduced first class functions as mainstream programming concepts.
It's also quite hilarious that the author lists fancy type systems as a definite No, but formal methods as a maybe.
While purely Functional languages are definitely not mainstream, as he puts functional programming ideas are pretty mainstream. At the same time major OO languages like java have incorporated functional programming ideas, so arguably even Java is not purely Object Oriented anymore. It seems to me by his criteria that would also put OO as a no too.
If he comes from OO languages I think this is a bias because it is easy to take OO for granted and put strict requirements on foreign Functional Programming before accepting it as successful. However it seems to me the only criteria that should be needed to call either paradigm successful is if their ideas are are mainstream, which is true for both languages.
Basically if Function Programming ideas have gained currency then it should be regarded as successful.
Especially considering most programming languages have those neat helper methods or stdlib implementations that basically bring functional programming without changing the language much.
Just one thing: when you write that Ruby script, could one of the reasons why you don't use a FP style be not only that maybe it wouldn't be natural to do so in Ruby, but also that it's unsuitable for the kind of problem you are trying to solve with that script to begin with?
I mention this, because I have the impression that people tend to believe that to solve a programming problem you should use whatever paradigm is perceived as the main one for the language at hand. However, I believe that it's the problem that should dictate the paradigm.
But the thing is, what if you are stuck with a given language, and/or its a biggish complex project where different aspects are better solved with different paradigms?
-Scala was intended to have strong FP and OO support from day 1
-Scala has very strong support for immutable values and persistent data structures. It's hard to do FP efficiently without these
-Similarly, Scala has built in support for laziness to a significantly greater extent than most languages. This is arguably important because it supports immutability, there are some important mutable algorithms that have no efficient immutable equivalent without laziness
-Strong lambdas (unlike, e.g., Python)
-Many of the major Scala libraries are either written in a heavily functional style or support highly functional APIs, while libraries in most languages do not
I'd say it's a language whose issues are sometimes something that FP is best at papering over, but as an FP language, it is quite lacking if you're used to something like Haskell, Erlang, or Lisp. I actually put it in the category of OO-FP languages, languages that have a lot of the FP constructs (especially from when Lisp was the epitome of FP) but are primarily object-oriented languages. It's a pretty decent paradigm, but it really ought to be distinguished from FP languages where there are no OO features in them at all, or much more rarely, where they are clearly second-class.
JS doesn't really support traditional inheritance either, so describing it as OO seems odd to me.
And even within my ecumenicalism, I consider inheritance in the strictly C++/Java sense of relatively little importance, and dropping. Rather than being essential, it turns out to have been accidental, and also arguably a mistake, even on purely OO grounds.
FP is by no means restricted to purely functional languages. My impression is that the ideal approach is to use the paradigm most suitable for the problem/component at hand (principle of least expressivity), so I prefer multi-paradigm languages over pure ones, although of course I understand that there are domains where one can benefit from the optimizations made possible by purity.
Understanding how to do this requires much more of a learning effort, learning more concepts, techniques and idioms, which I suspect is why FP is still lagging; I don't believe it is for any fundamental reason.
The other thing is that there are many more programming paradigms than just functional and stateful.
Just because something isn't "the most popular" doesn't mean that thing doesn't work.
In OP's article, OO is filed under "what works", which I strongly disagree with. If anything, software development works DESPITE OO, which in my experience constantly hinders progress because of rigid architectures.
FP is less popular and tends to attract a more curious crowd, who is more willing to learn how to use it well, whereas OO languages are used by everyone.
On top of that, OO is build on top of a more expressive computation model, the stateful one, which because of its power is much more difficult to use well (and easier to abuse) than the much simpler functional/declarative model.
That's similar to what proponents of communism have been saying - "it does work if you do it right". The problem is that things start breaking down as soon as the project scale. For small programs a pure OO model can work, but increased complexity means people will definitely switch to a hybrid OO-(procedural|functional) style, simply because pure OO is untenable in large codebases.
Not sure what it is like for the industry at large, but from what I've seen a dominant paradigm in Java is to separate out model classes that are basically just structs with Service or Workflow classes that manipulate the data. It's questionable how much of that is still OO (at least when I started learning it the narrative was to put your code where your data is. POJOs are the opposite of that). Given say having a high level service that calls low level services and external system while returning a result produces code thats very easy to trace and provides solid abstraction to the calling code. Also if you've read Uncle Bob's data structure vs. Object dichotomy you'll see how Objects are objectively better in some scenarios, and OO languages give you powerful tools for objects.
That said 100% agree with you on horrible inheritance hierarchies. What I think would be best is some course on how to combine OO and FP paradigms to get the best of both worlds (though tbh it'd probably be 90% FP with some OO).
If you want to find out, read "Concepts, Techniques, and Models of Computer Programming". It's mindblowing. It answers that question exactly.
This is a dense but exceptionally written 1000 page book, but maybe you can just read section 4.8.5 to get an idea [1]. However, I think you will take more than just reading this bit, to understand the different models (many more than the 2 everybody talks about).
Section 4.8.7 is actually "Using different models together", with the key "impedance matching" concept.
The author sort of summarizes it here [2]
There is also a mooc in edx, but it just scratches the surface of what's in the book [3]
[1] https://books.google.com.vn/books?id=_bmyEnUnfTsC&pg=PA322&l...
[2] http://lambda-the-ultimate.org/node/4698
[3] http://lambda-the-ultimate.org/node/4842
I leave this article out whenever people start talking "OOP vs FP": https://eli.thegreenplace.net/2016/the-expression-problem-an...
https://trends.google.com/trends/explore?date=2007-01-01%202...
Things aren't looking so hot for ML style languages like F#, Ocaml, and Haskell either:
https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0...
The only functional programming language that is showing any real growth is Scala, but that is also modest compared to the ones that are already much bigger or growing much faster:
https://stackoverflow.blog/2017/09/06/incredible-growth-pyth...
Where functional programming is growing is in existing large OO languages. All of them now have lambdas. Most have mature immutable and composable data structure libraries. And other functional style syntaxes like pattern matching are being introduced in many of them.
https://trends.google.com/trends/explore?date=today%205-y&q=...
The Interpreter and its dual the Visitor GOF pattern have made what amounts to pattern matching possible in OO languages for a few decades now [1].
The whole point of these patterns is to write recursive functions following recursive data types, which is one of the main use cases for pattern matching (ok, more generally these are used to break data structures apart).
In particular, if you look at an example of the Visitor pattern, you will see that it has exactly the same structure as a recursive function that separates cases in a FP language [2]
Here is a detailed explanation of how to do it [3]; it is the "little language" technique (which I suspect is the reason why it is called the Interpreter).
[1] https://eli.thegreenplace.net/2016/the-expression-problem-an...
[2] http://blog.higher-order.com/blog/2009/08/21/structural-patt...
[3] https://ocw.mit.edu/courses/electrical-engineering-and-compu...
In some ways the Android/iOS permissions system is a form of "capabilities". Granularity is a problem: too granular and they're tedious, not granular enough and you end up leaking your contacts to your torch app.
It's just an unfortunate pun. Capability-based security wasn't mainstream at the time they were invented. It arguably isn't now either. You can argue that Android/iOS are capability-based, but the model is pretty watered down.
Capability-based security for end users (rather than sys admins) is an unsolved problem as far as I can tell.
See this page:
https://en.wikipedia.org/wiki/Capability-based_security
A capability (known in some systems as a key) is a communicable, unforgeable token of authority.
Linux capabilities don't meet this definition. They're just permissions.
The sibling comment is also correct:
https://news.ycombinator.com/item?id=15807241
First, what's the problem? http://www.cap-lore.com/CapTheory/ConfusedDeputy.html
What are capabilities? http://habitatchronicles.com/2017/05/what-are-capabilities/
Is there someplace with a massive pile of links? https://github.com/dckc/awesome-ocap
Yes, capabilities are abstract and simple. Don't worry if you don't get it at first.
My cell phone begs to differ.
The highest leverage I've found comes from spreadsheets and relational databases because they require little or no code to accomplish so much. So I think that declarative or 4th generation programming languages deserve an honorable mention in the "yes" category.
The lowest leverage has been on the object-oriented side, especially with C++. Java is the least abstract language I've used in recent memory, due to its obsession with staying as far from functional programming as it can (closures were accomplished with anonymous objects until version 8!). There is simply no way to infer where a value was set without tracing the entire code, which slows development time by a factor of 10 to 100 over more functional techniques that use methods to derive state instead of values. So I think the "No" category needs a mention of highly imperative code and its tendency to become spaghetti.
The single most damaging practice I encounter daily is the breaking of convention and the loss of programming context that we've built up in our minds over the years. So while most functional programming languages are conceptually brilliant, they stray so far from mainstream languages like Javascript that I think they complicate syntax unnecessarily. Heavy-handed patterns also urge us to segregate code into parts when the logic doesn't require it, which I often find unintuitive. Mobile development especially, with its obsession with delegation, event broadcasting, observers and nondeterministic behavior of partially uninitialized views (especially recycler view and UITableView) feels like always having to remember 10 or 20 digits when we can only comfortably manage 7. Types for the sake of types will likely expand code size and complexity by an order of magnitude when a simple compiler would have accomplished nearly as much. I have low confidence that any of these will survive the next tech bubble.
I view parallelism and AI as a great uncharted sector of computer science that was stifled by Microsoft, Apple, Intel and NVIDIA. Had FPGAs or open source graphics cards taken off after the 90s, we would have a very different view of things like the Actor model (Erlang, Go, etc). So shared threads are a huge "no", but the private address spaces/streams/message passing and copy-on-write model of UNIX is a huge "yes" and we'll likely see these techniques adopted at the language level in the next decade. It would also be nice to have the numerical computing techniques from MATLAB so we can operate on matrices instead of primitives and saturate the hardware with less effort. Under these tools and conventions, AI loses much of its mystery because you realize you can always brute force a solution and evolve more elegant ones later to find a better local optimum.
Just look at Reason. They make OCaml more userfriendly for JavaScript devs, and FP-people are hating that the language loses all its beauty...
Java has had closures through inner classes since the beginning, albeit admittedly in a verbose way. This is a quote from page 540 of "Concepts, Techniques and Models of Computer Programming": Full lexical scoping. Full lexical scoping means that the language supports procedure values with external references. This allows a class to be defined inside the scope of a procedure or another class. Both Smalltalk-80 and Java support procedure values (with some restrictions). In Java they are instances of inner classes (i.e., nested classes). They are quite verbose due to the class syntax (see the epigraph at the beginning of this section).
But I think this is already enough to do high order programming, given that it effectively allows having functions as values (and hence high order functions), and support all 4 basic techniques high order programming builds upon: procedural abstraction (which relies on closures), genericity, instantiation and embedding [1].
I have to admit that I am not sure if I understand what you mean by "There is simply no way to infer where a value was set without tracing the entire code, which slows development time by a factor of 10 to 100 over more functional techniques that use methods to derive state instead of values". My (possibly wrong) interpretation is that you are referring to lazy execution, given that this technique associates a variable with a function that creates its value but whose execution is delayed until triggered when the value is actually needed.
Is this correct? If it is, then explicit lazy execution can certainly be accomplished in Java, given that, as I have said before, it allows embedding procedure values in a data structure. Of course, this is not as convenient as implicit lazy execution as in Haskell with its non strict evaluation, but it achieves the main purpose of laziness all the same, which is to optimize resources by allowing consumers rather than producers to drive value creation and hence generate data structures incrementally (as they are needed) rather than eagerly (as in simpler data driven techniques): stream programming; another advantage of laziness is of course purely functional persistent data structures in some cases with good performance ([3] and [4]).
"It would also be nice to have the numerical computing techniques from MATLAB"
I couldn't agree more with this. For instance, if possible, for a ML project I think it's better to do as much research/experiments/development as possible in Matlab/Octave, and then translate it to Python or whatever the production language is (would love to hear opinions on this). It would be so nice if such translation could be avoided (maybe a preprocessor could automate it, but still ...).
I believe that the reason is that Matlab is just a much more natural language for mathematical programming. I did the wonderful mooc [2] in Matlab, and much prefered it compared to the Python solutions I saw.
[1] https://ocw.mit.edu/courses/electrical-engineering-and-compu...
[2] https://www.edx.org/course/learning-data-introductory-machin...
[3] http://lambda-the-ultimate.org/node/2665
[4] https://www.cs.cmu.edu/~rwh/theses/okasaki.pdf
1) I have realized that systematically learning programming concepts, models and algorithms first, and how to apply them through programming techniques is much more important than just keeping on learning new languages and frameworks. For this, I am finding "Concepts, Techniques and Models of Computer Programming" invaluable; it covers an amazing amount of ground, and has an excellent bibliography to know where to learn more of a particular aspect. It is is a successor of SICP, which is very good too, and, I suspect as a tribute, is the first reference in CTM.
2) Learn how to do lightweight design upfront based only on the problem/requirement independently from language; the book above helps enormously, but I also really like the approach in the 2008 version of the MIT course 6.005 (later versions are watered down IMHO) [1]. It reinforces this design approach, and has, AFAIK, the best approach to using Design Patterns properly and systematically: to bridge the gap between design and code, which this way just flows almost automatically from the design. It may not be immediately obvious, but this course has a lot in common with SICP. For this reason I am highly sceptical of TDD, although I love to write the tests first and incrementally.
3) Once you know 1), many aspects of learning a new language and using it well are a piece of cake, because what you learned in 1) transcends any particular language and is timeless; I am now starting to enjoy mapping what I learned in 1) to different languages.
4) if you have to or want to use a language that is lacking direct support for anything in 1), if the language's computing model allows it (and many do, it is amazing how adding just one little concept to a language opens a whole range of possibilities but also problems, i.e. destructive assignment, threads, exceptions, triggers, ports, dataflow variables, etc), you can just build an abstraction or find a mature library that implements it. It is equally amazing how much you can still accomplish even if you remove one of the those concepts from a language, like destructive assignment, if you know the right techniques. It may not be as efficient and convenient as a built in abstraction, but will very likely still be much better than the alternative of implementing a design that is not the right one for the problem/requirement.
5) there is no need at all to be intimidated by a language or system with an enormous amount of features/libraries. Most of the time you only need to select a subset of the language to accomplish your goal efficiently. From 1) you will learn exactly how to do this and exactly why it is crazy to try to use the full power of a language; you should actually do the exact opposite, use as few concepts of a language as you can get away with while still writing a program that has a good balance of all required good properties.
[1] https://ocw.mit.edu/courses/electrical-engineering-and-compu...
Oops, I have just realized that I misread this totally. Apologies.
>" DEC started a project to do dynamic translation from x86 to Alpha; at the time the project started, the projected performance of x86 basically running in emulation on Alpha was substantially better than native x86 on Intel chips."
I'm really curious how an Alpha emulating x86 could be faster than the native x86? Can someone shed some light on how this would be possible
So perhaps they were overly optimistic.