Yesterday I had a small epiphany regarding the use of ternary operators in lieu of if else statements. I initially learned to program in Perl, which left me accustomed to certain convenient operations that are not readily available in most other languages (at least not with the same elegant presentation). The one that is most relevant right now is what I will call the “binary operator” in reference to the well known “ternary operator” (action ? condition : other action). Perl allows programmers a very hackish use of the or operator, || in which any action can be followed by || and an alternative action is given if the initial action fails. An example of this binary operator would be:
> my $foo = $bar || "You silly goose, there's no variable \$bar defined!";
This operation (assuming that you’ve told the perl interpreter to choke with the appropriate options) will assign the string in the second half of the statement to the variable $foo. This is because attempting to read from $bar fails and gets passed to the || operator as a false, therefore triggering the second half of the statement, which then evaluates and is assigned to $foo.
This behavior relies on an aspect of Perl in which all assignments, etc. return a value, and if this return value is not apparent (i.e., $x = y), the return value is likely true or false to indicate success or failure respectively. Exploiting this seems extremely hackish to many when they first learn of this, but it quickly becomes apparent that it is necessary in defining subroutines (the term Perl uses for functions) that take a variable number of arguments.
Subroutines in Perl do not define the arguments that they take in their header. Instead, the interpreter assumes that the subroutine will take an array of any length as its argument, which is then stored in a locally scoped array named @_ (I will be writing a post on the beauty of sigils and context in Perl and how they create a deceptively strong type system). To most cleanly assign arguments to variables in subroutines, statements of the form my $argument = shift, where shift assumes that the array in question is @_ and it destructively updates the array, returning the first item and removing it from @_. An example of this would be the following:
> sub takes_args {
> my $first_arg = shift;
> print $first_arg;
> }
This function takes a list of any non-zero length and prints out its first element. Often, however, you may want a default option. This is useful for constructor classes in object oriented programs, or for functions that may take additional arguments to further hone behavior (such as python’s range(x,y) function, which can take a third argument that indicates the step to take). This is where the binary operator becomes epically useful. An example follows:
> def has_default {
> my $foo = shift || "This is a default value!";
> print $foo;
> }
Having explained things this far, I hope that this code should be easy to understand: It takes a list as an argument of any length, and if it is of non-zero length, print the first argument, otherwise print "This is a default value!". There is one other very common use case that tends to amuse users of Perl: the “or die” construct. Perl has a “kill the program and possibly print an error message out if one is provided” function called die. This is what you might want to do if a user provides input that exceeds a certain range, or if you just want to be a bitch and kill your program in one easter egg scenario. In any case, you again rely on the return value of all operations and make a statement like this:
> def feed_me {
> my $input = shift || die "FEEEEEED MEEEEEEE."
> print "Omnom delicious input.";
> }
This code requires input or else it will kill the whole program and yell at you. This has great applications when there is some program critical operation that must complete in order to continue, or if there is a specific state that you want your program to avoid. This operation, one might notice, is less useful in OOP and more useful in procedural programs (Perl, while having OOP capabilities, is a procedural programming language first and foremost).
And this fine construct is why I need to use ternary operators. The logic may not be apparent (or just seem wrong), but having such a convenient operator so handy leaves a distinct imprint on a person’s programming style, and if I can write code that feels more natural to me, is there any good reason to not do so?
Posted in:
Code
by
Lex
/
Tags: coding pragmatics, Perl
2 Comments