1

I am writing new Perl 5 module Class::Tiny::ConstrainedAccessor to check type constraints when you touch object attributes, either by setting or by getting a default value. I am writing the unit tests and want to run the accessors for the latter case. However, I am concerned that Perl may optimize away my accessor-function call since the return value is discarded. Will it? If so, can I tell it not to? Is the corresponding behaviour documented? If the answer is as simple as "don't worry about it," that's good enough, but a reference to the docs would be appreciated :) .

The following MCVE succeeds when I run it on my Perl 5.26.2 x64 Cygwin. However, I don't know if that is guaranteed, or if it just happens to work now and may change someday.

use 5.006; use strict; use warnings; use Test::More; use Test::Exception;

dies_ok {   # One I know works
    my $obj = Klass->new;   # Default value of "attribute" is invalid
    diag $obj->accessor;    # Dies, because the default is invalid
} 'Bad default dies';

dies_ok {
    my $obj = Klass->new;
    $obj->accessor;         # <<< THE QUESTION --- Will this always run?
} 'Dies even without diag';

done_testing();

{   package Klass;
    sub new { my $class = shift; bless {@_}, $class }
    sub check { shift; die 'oops' if @_ and $_[0] eq 'bad' }
    sub default { 'bad' }
    sub accessor {
        my $self = shift;
        if(@_) { $self->check($_[0]); return $self->{attribute} = $_[0] }   # W
        elsif(exists $self->{attribute}) { return $self->{attribute} }      # R
        else {  
            # Request to read the attribute, but no value is assigned yet.
            # Use the default.
            $self->check($self->default);    # <<<---- What I want to exercise
            return $self->{attribute} = $self->default;
        }
    } #accessor()
} #Klass

This question deals with variables, but not functions. perlperf says that Perl will optimize away various things, but other than ()-prototyped functions, it's not clear to me what.

In JavaScript, I would say void obj.accessor();, and then I would know for sure it would run but the result would be discarded. However, I can't use undef $obj->accessor; for a similar effect; compilation legitimately fails with Can't modify non-lvalue subroutine call of &Klass::accessor.

cxw
  • 16,685
  • 2
  • 45
  • 81
  • Huh? `perlperf` is about tips and tricks to improve user code. It has nothing to say about any internal optimizations made by the perl compiler. – mob Mar 14 '19 at 17:14
  • Regarding "the result would be discarded", in Perl this is just void context and any function can be called in that way. Your example won't necessarily apply void context because it will be called in whatever context dies_ok calls the surrounding function (the last statement evaluated is the implicit return value of a function), but you can put a dummy return value afterward so the statement is always in void context: `$obj->accessor; 1;` – Grinnz Mar 14 '19 at 22:17

1 Answers1

1

Perl doesn't ever optimize away sub calls, and sub calls with side effects shouldn't be optimised away in any language.

undef $obj->accessor means something similar to $obj->accessor = undef

ikegami
  • 367,544
  • 15
  • 269
  • 518
UjinT34
  • 4,784
  • 1
  • 12
  • 26
  • 3
    It would be nice to have stronger references/justifications to your answer than just "AFAIK". – Dada Mar 14 '19 at 15:15
  • 2
    There are millions of lines of Perl code with function calls that don't use the return value. I am very comfortable endorsing Ujin734's view that Perl will never optimize them away. – mob Mar 14 '19 at 17:26
  • 1
    It would be a bug if anything with possible side effects was optimized away. – Grinnz Mar 14 '19 at 22:13