-
9 votes
-
Weekly coronavirus-related chat, questions, and minor updates - week of September 7
This thread is posted weekly, and is intended as a place for more-casual discussion of the coronavirus and questions/updates that may not warrant their own dedicated topics. Tell us about what the...
This thread is posted weekly, and is intended as a place for more-casual discussion of the coronavirus and questions/updates that may not warrant their own dedicated topics. Tell us about what the situation is like where you live!
8 votes -
Weekly thread for news/updates/discussion of George Floyd protests, racial injustice, and policing policy - week of September 7
This thread is posted weekly - please try to post relevant content in here, such as news, updates, opinion articles, etc. Especially significant updates may warrant a separate topic, but most...
This thread is posted weekly - please try to post relevant content in here, such as news, updates, opinion articles, etc. Especially significant updates may warrant a separate topic, but most should be posted here.
8 votes -
Kabaddi: The ancient game that's gone pro
11 votes -
Supersonic baseball cannon (World's fastest baseball)
7 votes -
Back to the land - Alice Driver writes about her father, a potter, and his ongoing project of building his own tomb as his final creative act
6 votes -
Mercenary black riders and the evolution of cavalry warfare in the 16th century
4 votes -
As the first major blockbuster to release since the start of the pandemic, Tenet opens to $20 million at US box office and nears $150 million internationally
15 votes -
Auto industry TV ads claim right-to-repair laws would benefit "sexual predators"
18 votes -
Windows 10 Ameliorated review
13 votes -
The new neuroscience of stuttering
8 votes -
GWU investigating whether White professor invented her Black identity
7 votes -
Is there a Google-free future for Firefox?
27 votes -
Conlang Critic: Lingwa de Planeta
4 votes -
US President Donald Trump eliminates federal anti-racism training, calling it “a sickness”
30 votes -
Different types of 3D platformers
Spurred by this (sub)thread on the topic of 3D Mario All Stars, I thought it would be interesting to discuss different types of 3D platformers, comparing them and perhaps even managing to group...
Spurred by this (sub)thread on the topic of 3D Mario All Stars, I thought it would be interesting to discuss different types of 3D platformers, comparing them and perhaps even managing to group the similar ones together.
I hope such a discussion might lead people to try some other games that they haven’t before based on what they have enjoyed before.
Some example topics, to kick-start the discussion:
- how the character feels/controls (e.g. their momentum, jump, move-set)
- audio-visual package
- story and general ambience/feeling
- completionist goals
- specific game mechanics
- any other reason why one is a “must play” and how is it similar or different to others
- …
8 votes -
Inside Amazon’s secret program to spy on workers’ private Facebook groups
7 votes -
Do you separate the art from the artist?
I'm having a hard time with this. I stopped listening to some bands because of what they did, do or not do. The guy from Inquisition turned out a pedophile. Mgla, while not a nazi band per se, are...
I'm having a hard time with this.
I stopped listening to some bands because of what they did, do or not do.
The guy from Inquisition turned out a pedophile.
Mgla, while not a nazi band per se, are at least nazi sympathizers. So i stopped listening.
Vektor: the guy is a wife beater, but there are is some controversy.
And i absolutely loved these bands. While i can find similar bands, it's not the same.
But what i am doing not listening to it? I'm the one not listening to it and that's it. I will never give them money (i threw my Mgla shirt away) because i obtain the music by another means.
I am not helping with their popularity because i'm the only one in my circle that listens to these subgenres of metal and i mostly do it alone.
So... what's the point of depriving myself of music that i like? They are the ones who suck, not me! But at the same time i feel bad listening.
What are your thoughts on this?
23 votes -
Unstaffed, digital supermarkets transform rural Sweden – Lifvs start-up has opened nineteen stores across the country, choosing remote places that have lost their local shops
15 votes -
A comprehensive, deep dive into Tetris: The Grand Master (TGM) design, the hidden Japanese Tetris version you will never legally play
'sup. As promised, here's a text discussing the minutae of Tetris the Grandmaster, its sequels, and the game mechanics of Tetris in general. If you want more, there's some market analysis, drama...
'sup.
As promised, here's a text discussing the minutae of Tetris the Grandmaster, its sequels, and the game mechanics of Tetris in general. If you want more, there's some market analysis, drama and politics in the comment.
Tetris the Grand Master is probably the most beautifully designed game I know. I hope you will share my passion for this when your are finished with this post.
Since Tetris is a "pure" videogame where pretty graphics and/or enticing plot is irrelevant to the game†, this will focus a lot on the game mechanics.
Also: this is based on a draft script for a video I wanted to make for a while now. Presumably this thing would flow better with some illustrations at the same time. I tried to include some, but of course it's not the same as someone narrative over image.
Also: weird language ? Missing words ? Misplaced punctuation ? This probably comes from me, writing in English as a second language. Picture this article with a vaguely French accent if it helps (although I'm not actually French).
†I am aware of Tetris Effect. I am happy if people find TE a transformative transcendental synesthetic experience, but for this matter I much prefer Rez and particularly its Area X.
So: make yourself comfortable, get a hot beverage of your choice, perhaps enable the reader mode in your browser and prepare for a 4k-ish words long read.
Tetris, the arcade game
Tetris. The little game from the Soviet Union, the killer app of the Gameboy, and until Minecraft happened the most sold computer game of all time.
Despite its tremendous success, the general perception is that this title has not evolved since its initial release in 1984. We would effectively be playing the same game plus-or-minus some gimmicks and/or yearly graphical updates.
This is of course false. The evolution of Tetris game mechanics is a story for another time, but the skinny version is that there's two main branch to the Tetris tree: Nintendo, and Sega. What I want to talk about now is a representative of the Sega branch.
Did you know ? Sega means "Service Game". The company we know today as a publisher with a blue mascot originally sold arcade games. And even today, Sega has a strong presence in the arcade world.
Tetris the Grandmaster is an arcade game, made by Arika, a company made by ex-Capcom employee whose more notable works at the time include Street Fighter Ex.
Arcade game design is a delicate juggling act between two parties:- the game operator: wants money, and for single player game that could mean a short and/or difficult game.
- the player: wants fun. If the game is too difficult and/or unfair and/or incomprehensible, he or she will move to the next game
With this definition, vanilla Tetris is a pretty good arcade game:
As you play the game, the game ramps up in speed and consequently its difficulty. But it never feels unfair: you may complain having bad luck and getting a crappy piece distribution (more on that later), you are still responsible for that terrible stack you just made.
However, there's a finite limit to the speed of the game. Past a certain point, you end up in a kill-screen where it is impossible to play. The piece just falls and lock immediately, with you being powerless, unable to do anything.
How lock delay extend the base game
Video: Godlike high gravity NES Tetris game from JdMfX_, Godlike high TGM game from 777
What is remarkable with Tetris the Grandmaster is not only it has found a way to extend the base game past this seemingly hardcoded limit, but it also focus nearly all of its design toward this idea of speed. Speed is the focus of the game, and if you don't believe this, there's a giant chronometer at the bottom of the screen acting as a constant reminder.
So, how do you survive to the kill screen?
You could try to make the piece move faster (which they did) but this is not enough. At some point, the piece will still spawn on the ground and immediately lock.
Enter the Lock Delay.
Illustration: lock delay
Lock delay is the mechanic in which if a piece falls into the ground or the stack, it will not immediately lock but can react to play inputs and "slide" for a few frames before locking into the stack.
This has deep, deep consequences.
Obviously, you can make the game faster than anything we've seen before. All the while still have a viable game†. At maximum speed, or "20G" as it is known in the jargon, the piece directly spawns on the stack without floating at any point in the air.
†for the pedant: historically, Sega Tetris was the one of the first game to feature lock delay; and the mechanics was already there in some other falling blocks game such as Puyo Puyo.
At high speed, and especially at 20G speed, the piece movement becomes severely limited. Having the game viable at 20G completely re-contextualize the game, its moment-to-moment tactics and its general strategy. Not only you have to think about a given piece placement, but more than ever you have to take the next piece into account. Some sub-optimal piece placement or "bridges" have to be made in order to make the whole game continue.
Illustrations: possible piece placement at 2G, at 20G, at 20G with a bridge
And thus: while the core gameplay stays the same, the game becomes more demanding both physically and mentally. You have to react faster and input your command quickly and confidently; and at the same time you have to constantly think about your stack, the area where work is needed and how you can accommodate unwanted pieces. You can even manually control the pace of the game by cancelling the lock delay (done very naturally by pressing down.)
Lock delay is probably the most important game element added to Tetris, but it's not the only thing in which TGM also innovates. Several other additional mechanics exists, and they have this common idea of a "speed enabler". Let's review them:
"Speed enablers" game mechanics
DAS
I mentioned earlier that the way you move the pieces was faster. This seems like a straightforward thing to do at first sight but there's some subtleties hidden in it.
So: when you hold left or right, the piece moves automatically (in the jargon it's called DAS - Delayed Auto-Shift). It's a nice and natural movement akin to letting a key down in your keyboard, but there's actually two parameters to take into account.
First, how fast the auto movement is triggered, and second, then how fast the repeat itself is. In TGM, both happens at a brisk space (16 frames before auto-movement, and a movement of 1 case per frame). This is essential for 20G play. And, in the context of 20G, the DAS enable a family of movement techniques called autosynchro†that bring additional depth to the game.†manual synchro also exists, but requires significantly more skill, as it requires a 1-frame combination. Yup, just like in fighting games and their 1-frame links!
Wallkicks
There is another mechanic that involve automatic movement, called wallkick. A wallkick happen when you try to rotate a piece near a blocked cell, such as the stack or a wall. Normally, if the rotation mask overlap a blocked cell, the rotation will fail. However with wallkicks, the piece can automatically move so that the rotation can still happen. In modern standard Tetris, the rule of how the piece move is quite complicated (to my eyes) but enable advanced placement such as the infamous T-Spin Triple. In TGM however, it's dead simple: try to move one case toe the right or one case to the left in that order, and if the piece fits, it gets moved.
Illustration: wallkick
So yes: at first sight those wallkicks are concessions given to player that make the game easier. However, some advanced movement techniques takes advantage of wallkicks. The goal of course is to move a piece faster, leading to tiny but compounding time saves.^†
† in the jargon, optimal piece movement is called finesse
IRS
Continuing on the theme of rotation, let's now talk about the Initial Rotation System or IRS. So in most game, when a piece is locked, the next one immediately enters the playfield.
This is not the case with TGM: there's a tiny interval in which nothing happens (except perhaps a line clear animation). †.† of course there's a jargon term for this: it's called ARE††
†† it's not an acronym, it literally means "that thing" in Japanese (あれ)This interval have a dual purpose (Mark Brown would be happy): first, it serves as a buffer to charge the DAS. But it is not limited to rotation: you can also charge a rotation.
And that is what IRS exactly is: press a rotation button during this time and then the piece will spawn already rotated .
IRS usefulness is not only limited to make the game smoother to play: it solves a problem inherent to Sega Tetris. All game in that lineage have most piece spawning with a pointy end toward the ground†. This can be problematic in high gravity, and especially in 20G. If you IRS such pieces, you can then confidently slide them to the side without worry of them being stuck somewhere.
Illustration: trapped without IRS, saved with IRS
†why not having them spawn flat-side down ? I think this is partly for historical reason (establish a clear lineage with Sega Tetris), but also because this this extra-difficulty is coherent with an arcade game design.
And yes, of course, IRS is also a time saving measure, helping to shave some milliseconds here and there.
TGM history-based randomizer
Let's talk luck. Earlier on, I half-jokingly said that "luck" as a hallmark of a good game of Tetris. Well it is a bit more profound than that.
Any competitive Smash player can tell you this: consistency is king in a competitive game. That's why random event affecting the core gameplay are frown upon, and that's why tripping in Smash Brawl was so negatively received.
You can probably see where I'm getting at: there's one giant thing in Tetris that's by definition random: the way the piece sequence is generated. And yes, TGM has a optimized random generator, and in fact most Tetris game have one.An analysis of the history of the different random generator is a story for another time, but here's the gist of it:
In a purely random sequence of pieces, a sufficiently long series of S and Z tetraminos is bound to appear. Such sequences is mathematically proven to lead in a game over. Of course, this doesn't happen in practice. Especially in TGM, there's a finite number of piece given and thus the change of that happening is infinitesimally small.
However this does gives us insight about the piece distribution: flood (too much of a piece) and drought (not enough of a piece) is not fun. In other word, waiting for that g!%d!3mn long bar piece sucks.So how does TGM counteracts this ? It implements a history system that prevent recently given piece to be distributed again†. This is a flood prevention measure and make the game much more consistent while still having an element of unpredictability. And being unpredictable is not necessarily a bad thing, particularly in an arcade context where you still want the player to finish the game eventually. Fun trivia: modern standard Tetris nowadays implement an extremely predictable randomizer, which is mathematically proven to be infinitely playable at low gravity††.
†historically TGM is not the first game to implement a history system, there was already a rudimentary one in NES Tetris
†† this is less of a problem in recent years due to the focus on multiplayer, enabling stuff like openers, but this is a story for another timeConsistency in randomness is not directly tied to the notion of speed, but being confident in that you will not screwed by the piece distribution definitely helps in the elaboration of reliable strategies.
The graphics helps too
Illustration: An actual screenshot of TGM
So far I've describe how the game is mechanically inclined toward speed, but aesthetically there's also some elements that are helps during high speed games.
First, look at what the stack and notice how the active piece contrasts with the rest of the stack. There's a clarity of graphics that comes not only by the fact that the locked pieces have a darker hue, but also because of the of this white border that surrounds the stack. The goal is to have an instantly readable playfield.
Continuing on this trend, each piece type is color coded so you can instantly read what you're getting by using your peripheral vision, leaving the focus clear on the stack. You can then more easily confirm the placement of your current piece, which is further helped by a very noticeable flash.
The next-piece window is also aligned so that the piece previewed is placed directly above where it will spawn. This unconsciously helps the tactical decision of where to put your piece. Speaking of unconscious effect, the whole series have this auditory gimmick in which each pieces have its own jingle. From what I know, nobody use this consciously, even the one that can tackle the invisible challenge (more on the invisible challenge later).
Scoring, grading, and speedrunning
So we've seen the mechanics and the aesthetics of speed within TGM.
But what would would be an arcade game without a good I piece measuring contest ?
TGM has three metrics exposed to the player: Score-grades, level and time.
Time is a straightforward metric, and is the main point of comparison for players having reached the Gm grade. Finishing the game under 13 minutes is ok, under 12 min is pretty good, under 10min is exceptionally good, and approaching 9min is godlike.
Score, as in most videogame is a measure of how "good" you are at the game, but takes here a subtly different meaning. The exact detail of the scoring system is not super interesting to see†, but its implication is. Let me explain:
† here : Score = (roundUp((Level + Lines)/4) + Soft) × Lines × Combo × Bravo ; Combo = Previous Combo value + (2×Lines) -2
The optimal strategy with this scoring system is to clear as much line as the same time as possible. In order words, Tetris, triples and even doubles†makes a lot of points, whereas Singles proportionally don't score as much points.
†Tetris: four line cleared at the same time; triple: three lines cleared at the same time; double: two lines cleared at the same ; single: one line cleared
This has an interesting side effect, as it incentivize to have a clean stack. A clean stack is a stack without holes. If there's holes in your stack, and particularly in they are all over the place, you tend clean them by performing singles. Sidenote: in TGM1, grade is directly correlated with score, except for the titular last grade, which is gatekeeped by some time requirements.
So in TGM, the score still describe how "well" you play, but you may have noticed that there's no notion of time at all†. I would argue that scoring here doesn't reflect how "well" you play but rather how "clean" you play. Keep that in mind for later.
†To be perfectly pedant there's the level factor in the equation that would incentivise you to play fast to reach high-yielding level as fast as possible. But please don't ruin my narrative.
I mentioned just before that the last grade had some time requirements. Now, this is a perfectly reasonable requirement for a game that is focused on speed but, and I guess you are used to me saying that, there's some subtleties to it.
Let's say the only requirement to get the last grade would be to reach X amount of point in Y amount of time, and reaching the last level. A viable strategy would be then to play as clean as possible so that you reach the point threshold, and then you just have to survive. This would mean that in that last part can play as sloppy as you want, you will still reach the Gm grade. That's, of course, not ideal as it doesn't push the player to play at its maximum (you can cheese the last part).
What TGM did is neat and two-fold: First, it takes the "level" metric, which was until then a measure of how fast the game is, and turned it into a progression gauge. So you know that at level 100 you are at the beginning of the game, 500 is midgame and 900 is the last push. The gravity is still tied to the level, so at level 0 it's quite slow and at 300 it's significantly faster. But the thing doesn't have to be linear or monotonic, in fact there's a speedbump at level 200 (people told me it's for dramatic effect), and maximum speed is reached at level 500 (to let the new 20G gameplay shine.)
Now here's the catch: you can progress faster in the game by clearing lines. Indeed, the way you gain level is that you increase the counter by one each time you land a piece, but more interestingly you get a bonus level for each line cleared.
This ties everything together: if you want to play fast you have to play well, and if you play well the game will get faster.
This positive feedback loop is in fact a system with dynamic difficulty curve: as good players will be presented with a more appropriate challenge faster, as more novice player will get challenged at their pace.
So there you have it: even the scoring system is meant to go fast. Isn't that beautiful ?
The sequels
There were two sequels to TGM.
The first one, known as TAP within the community because of the subtitle of the final version of the game ("The Absolute Plus"), builds on the building block of the first. There's now a dedicated 20G mode with a brutal speedcurve to it (it is, after all, named "Death" mode). For the main game (now called "Master" mode), there's a much appreciated addition of an instant drop. This significantly speeds up the pre-20G game. The point system is now decoupled from the grade, and a secondary but hidden point system is used to calculate the player grade. The detail of which is complex, but the take-away effect is that consistency of play is now taken into account.
Video: a a TAP Gm game recorded during a livestream
The second sequel is known in the community as Ti (again with the subtitle: Terror instinct). It had implements some gameplay elements mandated by the Tetris Company: three pieces preview, a "hold" function, and floorkicks (i.e. piece can always rotate on the ground even if it collides with it). As a happy accident, this enabled TGM to go the even higher, borderline absurd, speed. I want you to look at the sheer insanity of the Death Mode's replacement: Shirase. And then look toward the end of the run where pieces turns into brackets (a nod to the real original Electronica60 version), nullifying the convenience of both color-coded pieces as well at the white-border. It's glorious.
Video: Cleared Shirase game by KevinDDR, the best Western TGM player.
Now, on the Master mode side, there's two major changes: there's a revamp of the progression/level system, where now the speedcurve itself becomes dynamic, and a further focus on consistency. You not only have to be consistent within a game, but also across games. Indeed, there's now an account system that is tied to an examination system. It inspects your performance and randomly challenges you with an special exam game in order to reach the grade it thinks you deserve.
The last grade is of course locked behind an exam, and is only reachable through that mean.Additional challenges
Sprinkled around the main game are some additional challenges that are a bit adjacent to the main game.
Illustration: A secret grade pattern build by ohshisaure
There's a ">" pattern you can built within the game. Doing so will award you a "secret grade" depending on how complete your chevron is. This is a nod to TGM predecessor (Sega Tetris), where bored players in the arcades invented this challenge and became popular. This is totally optional to the game, but really challenge your creativity, a bit like the golden and silver block in The New Tetris.
Video: KevinDDR and crew performance at AGDQ2015
And then there's the infamous "invisible" challenge first appearing in TAP. It is in fact a mandatory requirement to get the Gm grade. If, and only if, you played well enough in the main game, you are then presented with the invisible challenge during the credit roll, in which you have to survive during 60 grueling seconds.
I don't know the whys of this challenge, but I assume this is an extrapolation coming from the following observation: when playing the game, most players are in fact not directly looking at the stack (to convince you, look at this eye-tracked demonstration).
Looking at the stack only serves as some sort a placement confirmation, and so there's somewhere a mental model of the playfield. The invisible challenge thus forces the player to exclusively rely on this pre-existing mental model.
Fun trivia: the credit order is randomized so that you can rely on the name to estimate how much time is left.Conclusion
So that's it for this gameplay analysis.
Hopefully you'll understand now why some people play one or several of those games 15, 20 or 22 years after their releases. All games are still played and there's no "superior version" as each version has slightly different priorities on the theme of "speedy Tetris": Ti has raw speed, TGM is careful and methodical, and TAP is a happy medium between the two.
As a game designer, what general lessons can we learn from TGM ? I'm just a random dude on the internet, but let me suggest one:
"Brevity". I keep thinking back to a textual Let's Play I've read about the second addons of Neverwinter Nights 2 (Mask of the Betrayer) . During a story recap just before the game climax, Lt. Danger offers an analysis of the expansion and writes (highlight from me):
Instead let's focus in on what makes Mask good - and I think the answer ultimately boils down to 'brevity.'
[...]
Obsidian knew what they wanted to do with Mask and wrote it accordingly. Too often in games I find some puzzle, some encounter, that could have come from anywhere; the most egregious example is Bioware's reliance on the Towers of Hanoi puzzle (which thankfully has come to an end). There's too much that has barely anything to do with the premise or purpose of the story (if they bothered to have one at all). In Mask, though, I struggle to find wasted space. I've mentioned it before, but it bears repeating: there are no irrelevant sidequests. Every quest and every NPC ties back to the core themes in some way.If, looking back at your game, you can say "it's a game about X, hence Y", you may be on to something.
That's why remakes and sequels that "go back to their roots" are generally perceived as positive. It's an change to remove cruft and focus on the core of the game. Take Zelda Breath of the Wild for instance. Zelda 1 was a game about adventure, exploration and mystery. Hence: very few handholding, an open world, and no limits to exploration.
Of course, super-concise game shouldn't be the ultimate guiding principle of any given game. Case in point: I recently finished Yakuza 0. This is an excellent, excellent game, yet in terms of gameplay and pacing, it is all over the place: one moment you are in a crime drama, and five minutes later you're managing a cabaret club, and 10 minutes later you're in a karaoke booth singing
baka mitaiJudgement with a biker costume at the end.But brevity sure can sure made your game more elegant and enjoyable.
20 votes -
Rwandan single mothers turn to online babysitting of Japanese kids
12 votes -
makesite.py - Simple, lightweight, and magic-free static site/blog generator
7 votes -
US gives first-ever OK for small commercial nuclear reactor
19 votes -
Should we be able to view comments/posts where mods/admins are doing their roles and not doing them separately?
What I mean by this is: Sometimes @Deimos posts something related to his mod/admin work, like saying he will be locking a thread or adding something new, but that's not all he does, he makes...
What I mean by this is:
Sometimes @Deimos posts something related to his mod/admin work, like saying he will be locking a thread or adding something new, but that's not all he does, he makes regular topics and comments about regular things, he doesn't have need to use an alt-account for that. I feel that when he's talking or posting about his mod/admin work and talking about anything else that interests him should be able to be viewed separately.
Thoughts?
9 votes -
Why GitHub won't help you with hiring
10 votes -
Black Panther titles are free on Comixology
8 votes -
How Recettear changed PC gaming forever
3 votes -
RIP Jack Rickard, founder of Boardwatch magazine
6 votes -
An exploration of Project Zero Issue 2046, a seemingly unexploitable and simple bug in the V8 JavaScript engine that turns out to be exploitable in a very complex manner
7 votes -
Masnick's Impossibility Theorem: Content moderation at scale is impossible to do well
22 votes -
Two-metre-long sturgeon, a species today near extinction, has been found preserved in the pantry of a 500-year-old Danish royal shipwreck in the Baltic Sea
8 votes -
Arizona university prevents potential Covid outbreak by testing feces
8 votes -
What we’ve learned by comparing cash to job training
9 votes -
Looking for programming/software book recommendations
I'm not looking to gain any practical skills from these recommendations (ex: not "Clean Code", "The Pragmatic Programmer"). Last year I read through the two books in Fabien Sanglard's Game Engine...
I'm not looking to gain any practical skills from these recommendations (ex: not "Clean Code", "The Pragmatic Programmer"). Last year I read through the two books in Fabien Sanglard's Game Engine Black Book series and would love to get my hands on more books like them. Books that focus on history, arcane details and secrets once thought lost to time. Sadly it appears I've already worked through Sanglard's entire bibliography. But I'm sure there's more stuff out there like it.
10 votes -
Why do you feel lonely? Neuroscience is starting to find answers
7 votes -
Winamp in 2020 (Webamp Electron app)
13 votes -
Amazon deletes 20,000 product reviews written by seven of its top ten UK reviewers after a Financial Times investigation found they were written for profit
18 votes -
A brief look at programming paradigms
Overview If you've spent any significant amount of time programming, then you've probably heard discussions about imperative, functional, and declarative programming. These discussions are often...
Overview
If you've spent any significant amount of time programming, then you've probably heard discussions about imperative, functional, and declarative programming. These discussions are often mired in technical knowledge and require a fair amount of intuition when trying to grasp the differences between the examples placed in front of us. These different programming styles, usually called programming "paradigms", are discussed as if they exist within a vacuum with complete and total isolation from one another. This only furthers the confusion and frustration among newer programmers especially, which runs counter to the goal of instructing them.
In this post I'll be taking a look at the oft-neglected intersections where these paradigms meet with the hope that the differences between them will be better understood by reframing our existing knowledge of programming basics.
Note: I'll be using PHP for my code examples and will try to provide comments when necessary to point out language quirks.
Understanding Fundamentals is Imperative
Let's start by first reviewing the most basic, fundamental programming paradigm: imperative programming. The term is a bit strange, but the important thing to understand about it is that imperative programming refers to writing software as a series of instructions where you tell the computer how to solve a specific task. For example, if we need to add together a bunch of numbers inside of an array, we might write code that looks like this:
$numbers = [ 8, 31, 5, 4, 20, 78, 52, 18, 96, 27 ]; $sum = 0; foreach($numbers as $number) { $sum += $number; }This is a pretty typical example that you've probably encountered in some form or another at some point in your programming studies or career--iterate over an array one element at a time from the first element to the last and add the current element to some accumulating variable that starts at
0. The kind of loop you use may differ, but the general format of the solution looks the same. This is very similar to the way the computer itself performs the task, so the code here is just a relatively human-friendly version of the actual steps the computer performs. This is the essence of imperative programming, the basic building blocks of everything you learn early on.
Abstract Concepts
As the software we write gets larger and more complex, we then tend to rely on "abstractions" to simplify our code and make it easier to understand, reuse, and maintain. For example, if we've written a program that adds arrays of numbers together, then we probably aren't doing that in only one place. Maybe we've written a tool that generates reports on large data sets, such as calculating the total number of sales for a particular quarter, gross profit, net profit, remaining inventory, and any number of other important business-related metrics. Summing numbers could be so common that you use it in 30 different places, so to avoid having to maintain 30 separate instances of our number adding code from above, we define a function:
function sum($numbers) { $sum = 0; foreach($numbers as $number) { $sum += $number; } return $sum; }We do this so frequently in our code that it becomes second nature. We attach so many names and terms to it, too: DRY, abstraction layers, code reuse, separation of concerns, etc. But one thing experienced programmers learn is to write their functions and object and interface methods in such a way that anyone who uses them doesn't need to care about the underlying implementation details, and instead only need to worry about the method name, expected arguments (if any), expected return type (if any), and expected behavior. In other words, they don't need to understand how the function or method completes the intended action, they only need to declare what action they want performed.
A Declaration of Understanding
Anyone who has looked into the concept of the declarative programming paradigm should find those last words familiar: "they don't need to understand how the function or method completes the intended action, they only need to declare what action they want performed". This is the oft-touted explanation of what declarative programming is, the difference between detailing "how" and declaring "what", and I believe that it's this great similarity that causes imperative and declarative programming to become heavily entwined in a programmer's mind and makes it difficult to understand. Take this common example that authors tend to use to try to detail the difference between declarative and imperative programming:
// imperative function sum($numbers) { $sum = 0; foreach($numbers as $number) { $sum += 0; } return $sum; } // declarative function sum($numbers) { return array_reduce($numbers, fn($x, $y) => $x + $y, 0); }The authors will go on to state that in the imperative example, you tell the computer how to sum the numbers, whereas in the declarative example you don't tell the computer how to do it since you don't know anything about the
reduceimplementation, but intuitively it still feels as if you're telling the computer how to perform its task--you're still defining a function and deciding what its underlying implementation details are, i.e. the steps it needs to take to perform the task, even if its details are abstracted away behind function or method calls that could have varying implementation details of their own. So how the hell is this any different from defining functions like we do in imperative programming?The answer is simple: it isn't. We've used so many names and terms to describe functions and methods in our ordinary imperative programming, but the truth is that a well-defined function or method serves as a declarative interface to an imperative implementation. Put differently, declarative programming is defining and utilizing simple interfaces that describe what you want accomplished while the underlying implementation details are inevitably written using imperative code.
Functional Differences
Now we can finally tackle one of the biggest trends in programming right now: the functional programming paradigm. But to understand this paradigm, it's important to understand what a "function" is... from a mathematical perspective.
Yes, I know, math tends to be a enthusiasm sink for many, but don't worry, we're not actually going to be doing math. We only need to understand how math treats functions. Specifically, math functions usually look something like
f(x) = {insert expression here}, which is loosely equivalent to the following code:function f($x) { return {insert expression here}; }The important thing to note about functions in math is that you can run them a theoretically infinite number of times on the same input
xand still get the same return result. Unlike in a lot of the programs we can write, math functions don't produce side effects. Files aren't written to or destroyed, database entries aren't deleted, some global counter somewhere isn't incremented, and yourxdoesn't suddenly change. The idea behind functional programming is to embody some of that nature of mathematical functions because they're predictable and always reproducible, and therefore simple to test as well. For example, take the following:// not functional function increment(&$x) { // pass by reference--$x will be modified outside of this function! $x++; } $x = 1; increment($x); increment($x); increment($x); // functional function increment($x) { // pass by value--$x will NOT be modified outside of this function! return $x + 1; } $x = 1; $y = increment($x); $y = increment($x); $y = increment($x);Note that the first example will change the value of
$xon each call, meaning each subsequent call ofincrement($x)produces a different result. Meanwhile the second example doesn't change$xand so the return value ofincrement($x)is always the same. This may seem like a silly example, but in larger, more complex software this can be significant. So now that we have an understanding of functions from a mathematical perspective, we have everything we need to actually understand what functional programming is.Functional programming is a subset of declarative programming. Just like in declarative programming, you use simple interfaces to tell the program what you want to do rather than how to do it. But unlike declarative programming as a whole, functional programming imposes some additional restrictions on what you should and shouldn't do:
-
You should encapsulate behavior in pure functions, which always give a consistent output for a given input and don't have side effects.
-
You should write functions in such a way that you can compose them together, allowing you to combine and chain behavior to produce new functions or use the output of one as the input for another.
-
You should avoid side effects as much as possible.
-
You should avoid mutable state (e.g. changing the values in a variable).
-
You should avoid sharing state between components.
These restrictions would require an entirely separate post on their own to properly cover and have been covered so many times in so many ways by others elsewhere that it would be superfluous for me to try to add anything more. It's important to note, however, that these restrictions are imposed because they provide some key benefits. By avoiding side effects and by avoiding mutable and shared states, the code you write becomes more predictable and tracing the behavior of an algorithm becomes far simpler. By writing pure, composable functions, you create reusable building blocks that can be strung together in virtually any configuration with predictable results. This makes writing, reading, maintaining, and debugging code easier and less error-prone.
That said, I feel that it's important to note that in the real world when writing practical software that users can interact with, it's simply not possible to completely avoid side effects or mutable state. The very act of creating and updating database entries is itself an act of mutating state, which runs contrary to functional programming principles and is essential for many important software projects. But even if you can't adhere strictly to functional programming principles, it's possible to benefit significantly from being aware of them and integrating them into your own software development strategies.
Let's consider a more practical example to illustrate this. Imagine that you've built a social media website and you're trying to test a push notification system that will be triggered when your user receives a new message. Now imagine your code and unit tests look something like this:
function sendNotification(&$message) { // pass by reference--$message will be modified outside of this function! $notification_system = new NotificationSystem(); if(!$message['sent_push_notification']) { $notification_system->sendPushNotification($message); $message['sent_push_notification'] = true; } } function testSendNotification() { $message = [ 'user_id'=>'{some_id}', 'contents'=>'Hi!', 'sent_push_notification'=>false ]; sendNotification($message); sendNotification($message); }At a quick glance you probably wouldn't be aware of why the second message didn't send, but the fact that our
sendNotification()function mutates the state of the data provided to it is the culprit. This is code that doesn't adhere to functional programming principles since the data provided to it is mutated. As a result, running the function multiple times on the same variable doesn't result in the same behavior as the first call. If we wanted to work around this without adhering to functional programming principles then we would need to manually set$message['sent_push_notification'] = false;between function calls, which makes our unit tests potentially more error-prone. Alternatively we can make a simple change to adhere better to those functional principles:function sendNotification($message) { // pass by value--$message will NOT be modified outside of this function! $notification_system = new NotificationSystem(); if(!$message['sent_push_notification']) { $notification_system->sendPushNotification($message); $message['sent_push_notification'] = true; } return $message; } function testSendNotification() { $message = [ 'user_id'=>'{some_id}', 'contents'=>'Hi!', 'sent_push_notification'=>false ]; sendNotification($message); sendNotification($message); }Now both notifications will be sent out, which is what we would intuitively expect. You should also notice that the above is also a blend of imperative, declarative, and functional programming. Our function definitions have imperative code, our
sendNotification()function adheres to the functional programming principle of avoiding mutable state (well, mostly), and ourNotificationSystemobject provides a declarative interface for sending a push notification for a message.
Final Thoughts
By viewing these three paradigms not as completely separate concepts but as layers on top of one another, where functional programming is a type of declarative programming which is implemented using imperative programming, we can stop being confused by their similarities and instead find clarification in them. By understanding that imperative programming is the backbone of everything, that declarative programming is just simplifying that backbone with simple interfaces, and that functional programming is simply adding some additional guidelines and restrictions to the way you write code to make it more consistent, reusable, and predictable, we can start to see that we're not choosing one programming paradigm over another, but instead choosing how much consideration we place on the design of the programs we write. Except in purely functional languages, functional programming isn't some alien concept distinct from imperative or declarative programming, but is instead a natural evolution of the two.
There are a lot of details I've glossed over here. Each of these programming paradigms is far too detailed to include a proper analysis in an already lengthy post that tries to separate them from each other and clarify their differences. Blog articles exist in a thousand different places that can do each one far more justice than I can, and programming languages exist that completely cut imperative programming out of the picture. But for your average programmer slinging JavaScript, C, Rust, PHP, or what have you, I hope that this serves as a crucial starting pointing to understanding just what in the hell these functional programming enthusiasts are on about.
25 votes -
-
Malware in the wild using DNS-over-HTTPS (DoH) to pull payload
8 votes -
Online voting is much more difficult to do securely, and a fundamental problem with the concept is that most voters won't be able to understand whether it's secure or not
21 votes -
Justice (Part 1)
26 votes -
A next-generation version of The Witcher 3 is in progress, and will release as a stand-alone purchase as well as a free update for owners of the existing game
9 votes -
Good Music to Avert the Collapse of American Democracy
8 votes -
¡Se Queda! Lionel Messi’s Barcelona heartbreak revealed: From his son's tears, to refusing to go to trial - full truth behind 'brutal' transfer saga
3 votes -
Uber is hurting drivers like me in its legal fight in California
3 votes -
Amazon Alexa for Residential will let the voice assistant power apartment complexes
15 votes -
Digital pregnancy tests just contain a regular paper strip test and the battery, microcontroller, LEDs, photodiodes, screen, etc. are all to read whether it shows one line or two
16 votes -
SoftBank unmasked as ‘Nasdaq whale’ that stoked tech rally
11 votes -
Silk live-action Marvel series in the works at Sony Pictures Television
4 votes -
What have you been listening to this week?
What have you been listening to this week? You don't need to do a 6000 word review if you don't want to, but please write something! If you've just picked up some music, please update on that as...
What have you been listening to this week? You don't need to do a 6000 word review if you don't want to, but please write something! If you've just picked up some music, please update on that as well, we'd love to see your hauls :)
Feel free to give recs or discuss anything about each others' listening habits.
You can make a chart if you use last.fm:
http://www.tapmusic.net/lastfm/
Remember that linking directly to your image will update with your future listening, make sure to reupload to somewhere like imgur if you'd like it to remain what you have at the time of posting.
13 votes