Sieve Exercise: Reverse engineering perl tests to understand what results should look like

I’m currently working on the Sieve exercise:

When I run my function manually, I get the output expected based on my interpretation of the sieve.t file in the exercise. For example, consider the following:

is( # begin: 974945d8-8cd9-4f00-9463-7d813c7f17b7
    find_primes(10),
    [ 2, 3, 5, 7 ],
    "find primes up to 10",
); # end: 974945d8-8cd9-4f00-9463-7d813c7f17b7

is( # begin: 2e2417b7-3f3a-452a-8594-b9af08af6d82
    find_primes(13),
    [ 2, 3, 5, 7, 11, 13 ],
    "limit is prime",
); # end: 2e2417b7-3f3a-452a-8594-b9af08af6d82

Here is my function code (I’m sure it’s not optimal, but I’m more interested in why the results don’t pass) that I ran directly locally for testing:

sub find_primes ($limit) {
    my @nums = (2..$limit);
    say @nums;
    for (my $i=0; $i< $limit; $i++) {
        if(defined($nums[$i])) {
        my $iter = $nums[$i];
	say $iter . " is iter";
        my $running_iter = $nums[$i];
	say $running_iter . " is running_iter";
        while($running_iter < $limit) {
            @nums[$i + $running_iter] = undef;
            $running_iter += $nums[$i];
        }
    }
    }
    my @result = grep( defined, @nums);
    say \@result; #ARRAY
    return @result;
}
say find_primes(13); # 23571113
say find_primes(10); # 2357

Initially, I wondered if this was some artifact of my local linux environment. However, NONE of the tests pass in the web IDE either, which implies to me I’m doing something very fundamentally incorrect.

I see that the array is formatted in a run-on fashion when I print it, but I didn’t see anything about required formatting in the exercise so I assumed returning the above array should satisfy the requirement. What’s even weirder is that the results show nonsensical values for my test results:

# Failed test 'no primes under two'
# at t/sieve.t line 9.
# +-----+---------+
# | GOT | CHECK   |
# +-----+---------+
# | 0   | <ARRAY> |
# +-----+---------+

# Failed test 'find first prime'
# at t/sieve.t line 15.
# +-----+---------+
# | GOT | CHECK   |
# +-----+---------+
# | 1   | <ARRAY> |
# +-----+---------+

Anyway, would appreciate being pointed in the right direction. I’m doggedly trying to learn perl

Thank you for your time

Have you done the Perl syllabus?

The subroutine is returning an array, and as the subroutine is being called in scalar context, the return value is the number of elements in that array.

The expected result is an array reference. To return a reference, simply change the last line in your subroutine to return \@result;.

You can read more about references here: References in Perl on Exercism

The syllabus is incomplete so if there is something that is not clear do feel free to raise an issue for it.

I am doing all of the Perl content in the order available to me on the Perl learn track in the order they are available to me.
I’m trying to do every unlocked exercise to better understand the basics before moving on to more advanced concepts.
I simply added '' in front of \@result and the tests now pass. I saw scalar context in the readings, but in my recollection of what I read so far, I thought that was when you used ‘$’ as your sigil rather than ‘@’. I have not looked at references, and didn’t know that I could not return arrays directly as in Perl 6, javascript, Ruby, etc.

It looks like the link you supplied ‘References in Perl on Exercism’ is associated with the ‘Inventory Management’ exercise which isn’t unlocked for me:

Thanks for your assistance.

As a syllabus author myself, it’s tricky trying to associate learning exercises with concepts. You’ll find many exercises like this one where there are concepts you haven’t seen yet. I’d suggest you simply leave those for later.

1 Like

GIven the following test:

is( # begin: days-past task: 1
    appointment_has_passed( ( Time::Piece->gmtime - ONE_DAY * 23 )->datetime ),
    T,
    'Date days ago is in the past',
); # end: days-past

Does this imply that a correct version of this function appointment_has_passed should return ‘T’? This seems to be a variable or something, but it’s not defined anywhere in the test code.

Yes, that’s confusing, no doubt.

When you see a bare word like that in Perl, it’s a subroutine. If it was a variable, there would be a sigil.

Since you don’t see sub T defined anywhere, it comes from something you use. The likely candidate here is Test2::V0

I poked around a bit, and it is this: https://metacpan.org/pod/Test2::Tools::Compare#QUICK-CHECKS

$check = T()

This verifies that the value in the corresponding $got structure is true, any true value will do.

1 Like

A booleans concept is next on my list.

I’ll see what I can do to tweak the exercise, the instructions should be indicating that a boolean is needed but that may need some more clarification.

Implement the appointment_has_passed subroutine that takes a date string and checks if the appointment was somewhere in the past:

appointment_has_passed("2019-07-25T13:45:00")
// => true

What does your output look like when running the tests, they should also be giving some indication of what the expected results are? e.g.

# Failed test 'Date one minute ago is in the past'
# at /mnt/exercism-iteration/t/booking-up-for-beauty.t line 47.
# +---------+--------+-------+-----+
# | GOT     | OP     | CHECK | LNs |
# +---------+--------+-------+-----+
# | <UNDEF> | TRUE() | TRUE  | 47  |
# +---------+--------+-------+-----+

# Failed test 'Date one minute from now is not in the past'
# at /mnt/exercism-iteration/t/booking-up-for-beauty.t line 53.
# +---------+----------------------+-------------------+-----+
# | GOT     | OP                   | CHECK             | LNs |
# +---------+----------------------+-------------------+-----+
# | <UNDEF> | DEFINED() && FALSE() | DEFINED BUT FALSE | 53  |
# +---------+----------------------+-------------------+-----+
1 Like

Thank you both for the clarification.

I’m working on the functions one by one, in a separate file using say and manually running perl filename.pl to debug values as ::YYY was throwing an error in my tests. I guess the failure is too complete for output? Not sure exactly what Dubious, test returned 255 (wstat 65280, 0xff00) implies

sean@thonk:~/exercism/perl5/booking-up-for-beauty$ prove
t/booking-up-for-beauty.t .. Error parsing time at /home/sean/perl5/perlbrew/perls/perl-5.40.0/lib/5.40.0/x86_64-linux/Time/Piece.pm line 598.
t/booking-up-for-beauty.t .. Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run 

Test Summary Report
-------------------
t/booking-up-for-beauty.t (Wstat: 65280 (exited 255) Tests: 0 Failed: 0)
  Non-zero exit status: 255
  Parse errors: No plan found in TAP output
Files=1, Tests=0,  0 wallclock secs ( 0.01 usr  0.01 sys +  0.04 cusr  0.01 csys =  0.07 CPU)
Result: FAIL
[ble: exit 1]

Without seeing your code I can’t point out the exact issue, but I’ll break down each issue in the error message:

t/booking-up-for-beauty.t .. Error parsing time at /home/sean/perl5/perlbrew/perls/perl-5.40.0/lib/5.40.0/x86_64-linux/Time/Piece.pm line 598.

Something went wrong with the strptime method in Time::Piece. It looks like something may have gone wrong with the arguments being passed in as it appears to not be parsing successfully.

The offending line (assuming this is the same version of Time::Piece): Piece.pm - metacpan.org

t/booking-up-for-beauty.t .. Dubious, test returned 255 (wstat 65280, 0xff00)

255 represents a Linux exit code. They can be numbered from 0 to 255. 0 indicates success. With a Perl test file, if tests fail, the exit code is typically the number of tests which fail. If a Perl script dies, it has an exit code of 255, so this typically means there was an error which caused the code to die at some point.

1 Like

Thank you, ended up getting the code working, I was more stumped by the test outputs(and still wanted to figure out the code at that point) so that will help me understand better in the future.