Why would you write this in Perl?
September 3, 2010 1:17 PM   Subscribe

Can you explain to me a block of Perl? The tricky part is the last line, which is just a variable sitting on its own - no operation, no control structure, nothing.

sub data_source {
my $self = shift;
my $d = $self->{data_source};
$self->{data_source} = shift if @_;

I get everything except that last line, which really only makes sense if $d is some kind of function pointer. I'm under the impression that if that were so, &$d(); would be the correct syntax. I think I must be horribly confused in some way; can you help me out?

(code is from an open-source package with a busy author whom I don't want to bother with a possibly-basic Perl question.)
posted by yomimono to Computers & Internet (13 answers total) 2 users marked this as a favorite
Absent an actual return statement, the return value of a block is the last statement therein. That's just a shorthand for return $d.
posted by mkb at 1:26 PM on September 3, 2010


(In the absence of an explicit return, a subroutine, eval, or do FILE automatically returns the value of the last expression evaluated.)

You can test this with:

print mysub();

sub mysub {
$bar = "ABC";

posted by benzenedream at 1:26 PM on September 3, 2010

Subroutines in perl return the value of the last expression in the block, in the absence of an explicit return. In this case, should be equivalent to return $d;.
posted by Maximian at 1:27 PM on September 3, 2010

IIRC, it's the same as
sub data_source {
my $self = shift;
my $d = $self->{data_source};
$self->{data_source} = shift if @_;
return $d;
The result of last expression of a subroutine is returned even if you don't explicitly call return.

See: http://perldoc.perl.org/functions/return.html
posted by adirondack at 1:27 PM on September 3, 2010

Yeah that's a Perl thing - and the resulting confusion is a great reason why you shouldn't do things the "Perl-way".
posted by meowzilla at 1:28 PM on September 3, 2010 [2 favorites]

As someone who's been developing perl for a very long time, I hate little perl idiosyncracies like this. That, and handling additional function input parameters after the beginning of a function is a big no-no from a maintainability perspective.

To be as language-agnostic as possible, I'd have rewritten it like this:
sub data_source {
  my ($self, $new_source) = @_;
  my $d = $self->{data_source};
  if ($new_source) {
    $self->{data_source} = $new_source 
  return $d;

posted by swngnmonk at 1:39 PM on September 3, 2010 [1 favorite]

Thanks to all who answered. Don't I feel like a dope.
posted by yomimono at 1:39 PM on September 3, 2010

@swngmonk: your code does not give the same result. What if I want to set the data_source to undef? In the original, it works. But in your example, it does not.

That's because in scalar context, arrays evaluate to their length. In my example, @_ contains one element, undef, which means its length is 1 at that point. So the statement executes and sets $self->{data_source} to undef.

But in your example, it sees undef as false and skips setting $self->{data_source}. The only way to check if $new_source is really undef, or undef because @_ doesn't have enough items is to still check the length of @_ (in your case, it would be 2).
posted by sbutler at 2:25 PM on September 3, 2010 [1 favorite]

No, don't feel like a dope. The programmer that wrote that function should feel like a dope. It's good practice to write code as if someone else is going to have to edit and understand it. Maybe writing super-terse code like that is allowed by the compiler, but it's certainly doesn't help with readability or maintainability.

They say that hell is other people's code, but remember that hell is also your own code 6 months later.
posted by chrisamiller at 2:42 PM on September 3, 2010 [2 favorites]

In lots of languages, Perl, Ruby, Lisp, in the absence of an explicit return, the value of a function is implicitly the value of the last expression Personally, I'd have used a return in Perl (where it's conventional) but no return in Ruby or Lisp (where the absence is conventional.) But I have no quarrel with the implicit return.
posted by Zed at 3:14 PM on September 3, 2010 [2 favorites]

sbutler -

Not sure which code sample is yours (your comment on my sample), but I do concede that point.

I will reiterate chrisamiller's point, and add my general plea for proper comments around code blocks. As a matter of policy, I general administer beatings to anyone who says "just read the code" when looking for documentation on functionality for just this reason. Little subtleties like what you mention are not a hallmark of maintainable code.
posted by swngnmonk at 4:18 PM on September 3, 2010

According to Zed, this isn't a "little subtlety". It's the way a number of other languages work as well. It's a useful shorthand. And it's not, as meowzilla says "the Perl way" because as we've seen, it's not unique to Perl, nor is it the conventional way to do it in Perl. It would be nice, just once, to have a Perl question which didn't turn into a big sneer-fest or pile-on.
posted by AmbroseChapel at 5:26 PM on September 3, 2010 [5 favorites]

This is very common for pseudo-functional languages... the idea is that a function is basically a bunch of compositions of other functions and expressions, and splitting it up into statements like that is just a convenient way to write it in code. Sort of, more or less. It makes one-liner functions nice to write, and a lot of languages pick up the style. Ex from R: add = function(a,b) {a+b}
posted by devilsbrigade at 5:57 PM on September 3, 2010 [1 favorite]

« Older "if you replace each edge..."   |   I saved Latin. What did you ever do? Newer »
This thread is closed to new comments.