- Software Development
- Solving One Problem with 16 Programming Languages
A video blogger recently tackled the same programming problem using 16 different languages, giving viewers a chance to see a wide variety of results, share their own suggestions, and learn about programming languages along the way.
It was a fun demonstration of just how many choices there are in the complex world of programming languages today. But for at least one of the languages, it also turned into a demonstration of the power of a community.
The big event happened on code_report, a YouTube channel “dedicated to competitive programming”. It’s the work of Conor Hoekstra, a senior library software engineer at NVIDIA (working on its RAPIDS suite for data science and analytics pipelines) who’s also held roles at Amazon and Moody’s Analytics. Hoekstra also co-hosts a podcast about array-oriented programming languages and another one about programming-related topics like algorithms and data structures.
Fortran Has Fans
To explore 16 programming languages, Hoekstra chose a relatively simple problem from a LeetCode coding competition: Given a list of numbers, identify the smallest and largest number — and then find the largest number that can be divided into both of them (without a remainder).
The languages are chosen for the solution:
- Raku [Perl 6]
- Pharo Smalltalk
(The video explained that the last two languages were last-minute additions chosen by Hoekstra’s audience online. “I tweeted this out and asked my followers,” Hoekstra said, and Fortran received “a whopping 27 ‘hearts’ on a single tweet!”)
I can’t help but notice that this reply has the most likes. By the laws of the internet, you must include Fortran. ?
— Jeff Hammond asuu nyt Suomessa ?? (@science_dot) – August 25, 2021
Hoekstra called it “a pretty straightforward problem, but you’ll soon see, especially when we get to the array languages, that you can solve these in a drastically different way than compared to languages like Python or Ruby.”
The little differences quickly became apparent. Python already has built-in functions for all the necessary operations — for finding the smallest number, the largest number, and then the “greatest common divisor” that they share.
But things really started looking different when Hoekstra got to the functional language Haskell. Its liftM2 function basically maps the values from minimum and maximum into the input for the gcd function — all in a single line.
And best of all, since Haskell used so-called Tacit or point-free style programming, which doesn’t specify arguments in its function definitions, the Haskell solution didn’t even need to mention the array of numbers…
The low-level D programming language requires that the functions be imported — but at least that language uses universal functional call syntax, which lets functions be called using the familiar “method” style of object-oriented programming. Said the host, “This is really, really nice, in my opinion.”
With Rust, Hoekstra complained that, like C++, there’s “a lot of ceremony here” — in this case because the min and max functions require both the iter() method to actually iterate through each value in the list of numbers, and also the unwrap() method to extract just the value from Rust’s more complex enumerated Result type (which includes error handling information).
And, Hoekstra, noted: “there’s also a lot of noise in the num::integer:: namespace in order to get access to the gcd function. But other than that, it’s still a very nice solution.”
But there were even more significant differences, mostly because Hoekstra is a fan of array programming languages. With APL, the gist of the solution (to the right of the pink arrow) is just five characters. (The first two characters find the maximum value, the last two characters find the minimum value, and the green v in the middle finds their greatest common divisor.)
There’s a similar structure in the J programming language — also an array programming language — but “J is an evolved version of APL, and used ASCII diagraphs and not Unicode symbols,” Hoekstra noted. So the maximum-finding function is represented with >. while the minimum-finding function is <.
The solutions got more and more exotic. The BQN language is still an array-driven language in the APL family (according to the APL Wiki) — but BQN uses its own unique set of characters. Because there’s no pre-built function for finding the greatest common divisor, that function has to be defined in its own separate line of code.
Hoekstra admitted that he just copied the code from an online source. (“I don’t actually understand it, because I’m a BQN novice.”) But once it’s defined in the first line, it can be called as part of the solution in the second line.
Vying with Viewers
Judging by audience reactions, it looks like the internet enjoyed riding along and sharing the experience.
Some people on YouTube and Twitter were asking about a Cobol solution, so I decided to try my hand at it. https://t.co/Pi7OSCdeIl
It is ‘only’ 91 lines long…
— Wiebe Marten (@WiebeMarten) September 2, 2021
The video ultimately attracted 135 comments, where Hoekstra’s viewers shared their own opinions on programming languages (“The Haskell solution was beautifully elegant, APL was a bit too cryptic for me.”) as well as other comments on the proceedings. (“People that requested Fortran wanted to see you suffer.”)
Awesome video! And lol’ing at the absurd of FORTRAN’s solution
— joao (@_joaogui1) August 28, 2021
“I have received close to a hundred comments at this point, and a lot of them were improvements on the solutions that I showed in that video,” Hoekstra announced in a second video.
Julia’s solution had looked similar to Python’s — albeit with Julia’s “splat” operator (indicated by the three-dot ellipsis) to signify that more than one value will be tested.
But viewers had suggested a simpler syntax. Julia also has two built-in minimum- and maximum-finding functions which don’t require the ellipsis. There’s also a single function that returns both values — named extrema. And then the solution got even simpler when Hoekstra uses Julia’s composition operator to produce a point-free solution (with the collect function transforming the two values into a list format so it can be fed into gcd).
“In my opinion, this is the most beautiful solution of all,” Hoekstra added — partly because it demonstrates the elegance of point-free solutions.
Viewers had also suggested some elegant improvements for the solution Hoekstra wrote in Raku (the language formerly known as Perl 6). In Raku, gcd is an “infix” function that can be placed between two values just like mathematical operators (like a plus or minus sig). And then the two values that it’s operating on can be the results of object-style methods being called on the array of numbers. (Because, as Perl creator Larry Wall once said, in Raku “Everything is an object. But only if you want it to be.”)
Ironically, the Pharo Smalltalk solution also ended up resembling the Raku solution (with its own gcd: function also appearing as an “infix” operator between the two minimum- and maximum-returning functions).
But Hoekstra’s viewers had pointed out that Raku also has a dedicated minmax function that can return both values at once — resulting in another single-line solution where that result becomes the input for Raku’s gcd function.
“I do prefer this,” Hoekstra said. “Any time you can use an algorithm that’s going to do a single pass instead of two passes … I think that’s much preferable.”
Fun with Fortran
In the first video, Hoekstra ranked Fortran’s solution as the worst, calling it one of those languages cluttered with “ceremony.” But his solution came with a disclaimer. “Note that this is the first Fortran piece of code that I’ve written in my life, so odds are there’s probably better ways to do this … After 40 minutes of just getting this code up and running, I called it a day.”
But in the follow-up video, Hoekstra acknowledged that “The response that I got from the Fortran community was so amazing.”
The respondents included Jacob Williams, a Fortran programmer and orbital mechanic at the NASA Johnson Space Center.
Took about 5 minutes to write this (with gcd from rosetta code). I’m curious to know what documentation you were looking at to try to get yours to work. Good online resources are definitely something that #Fortran is lacking, although it’s getting better. @fortranlang pic.twitter.com/pqCiIVFQvV
— Jacob Williams (@DegenerateConic) August 29, 2021
And Hoekstra’s video also drew a response from Milan Curcic, a long-time Fortran programmer and author of the book “Modern Fortran.” On Twitter, Curic thanked Hoekstra for including Fortran and suggested an alternate implementation (which includes a greatest-common-denominator function that was proposed for the language in March).
Hoekstra learned that the temporary res variable wasn’t necessary, since the result could just be returned without separately assigning it. And some new syntactic sugar in Fortran now allows the length of a list to be indicated with just a colon — rather than Hoekstra’s unwieldy variable numsSize — which eliminates the need for an entire line of code assigning it to a dedicated variable.
“We went from what we had before to just basically two lines in the body of our function,” Hoekstra said. “So this, I thought, was absolutely awesome!”
He is thrilled that a new comment on its issue ticket on GitHub now even specifically mentions his video.
“The Fortran language Twitter account even retweeted my initial video tweet saying they’re going to work on improving their tutorials in the future, but just thanks for covering it — which I thought was awesome,” he added.
Hoekstra called the response “a model of how a community should act if they’re trying to get people to be more excited about their language.”
He concluded, “I hope you learned something from this video, as I definitely did from the comments.”
Solving One Problem with 16 Programming Languages: FAQ
What is leetcode?
How to solve leetcode problems?
LeetCode is available at three difficulty levels: Easy, Medium, and Hard.
- Begin with the easy tasks and work your way up to the more difficult ones.
- Begin with the questions that have received positive feedback. Not all LeetCode questions are made equal.
- Skip the ones you believe are too simple for you.
Going through the following steps:
- Recognize the issue
- Determine the data’s input and output.
- Make high-level pseudocode.
- Make the code.
- Improve the solution.
Let’s create the next big thing together!
Coming together is a beginning. Keeping together is progress. Working together is success.