💾 Archived View for gem.splatt9990.com › old_stuff › 20210118-Anaphoric_If.gmi captured on 2024-08-31 at 11:59:38. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-05-24)
-=-=-=-=-=-=-
So there's a concept that originated with Common Lisp but has made it's way to other programming languages. I'm talking of course about Anaphoric Ifs.
What the hell is that? Well, anaphoric is a ten dollar word that basically means that the thing its applied to is refering to something that came before it. In this case, that's referring to the condition of the if block in question.
Here's the original macro usage from Lisp:
(aif it (get-db-connection) (use-connection-somehow it) ;; else (error "couldn't get db connection"))
Unless you're reasonably familar with lisp though, it's probably not clear what's goin on in that code block. Here's an example using perl:
if ( my $con = get_db_connection() ) { $con->do_something(); } else { die "Couldn't get db connection"; }
In Lisp's case, the macro predefines a variable 'it' and assigns the value of the condition to it. In perl's case, we have to manually create a variable using 'my' (This is because anaphoric ifs in perl aren't a special construct, they share syntax with regular ifs.)
If you come from a python background, you might recognize this as the feature that (inexplicably IMO) caused enough uproar in the community to oust Guido Van Rossum as BDFL. It's a useful feature that keeps your variables in the exact scope it's needed in.
For instance, if your language of choice doesn't have this feature (several popular languages do not), you're probably used to having to do something like this:
const db = getDBConnection(); if ( db ) { db.doSomething(); }
While this pattern is fine in most cases, you probably don't want to declare db at the level above the if. It's more convenient and more (technically) correct to declare the variable in the if block, but without anaphoric if support in your language, you can't do so.
So perl actually has this feature in basically every block statement type it has. This includes while, for(each), and unless (which is just an inverted if). We use this feature frequently at $work as the ORM we use to fetch db results has an iterator function that fetches one record at a time rather than having to fetch *all* the records and then iterate over them.
my $resultset = $db->get_resultset(); while ( my $item = $resultset->next() ) { do_something(item); }
without such a feature, we'd have to manually set up this boilerplate every time we iterated over a resultset:
my $resultset = $db->get_resultset(); my $item = $resultset->next(); while( $item ) { do_something($item); ... $item = $resultset->next(); }
which is annoying and potentially error prone (it's *very* easy to forget to add the update line at the end of the while loop.)