14

I am attempting to work with a hash in Raku, but when I put some fake values into it (intentionally) like

say %key<fake_key>;

I get

(Any)

but I want the program to die in such occurrences, as Perl does, because this implies that important data is missing.

For example,

#!/usr/bin/env perl

use strict;
use warnings 'FATAL' => 'all';
use autodie ':all';

my %hash;
print "$hash{y}\n";

as of 5.26.1 produces

Use of uninitialized value $hash{"y"} in concatenation (.) or string at undefined.pl line 8.
Command exited with non-zero status 255

How can I get the equivalent of use warnings 'FATAL' => 'all' and use autodie qw(:all) in Raku?

raiph
  • 31,607
  • 3
  • 62
  • 111
con
  • 5,767
  • 8
  • 33
  • 62
  • Perl5 doesn't die if you reference a hash key that doesn't exist. – Scimon Proctor Jan 22 '19 at 16:53
  • @Scimon it will with `use warnings` which is what I want – con Jan 22 '19 at 17:03
  • `use warnings` won't make it die just throw a warning. – Scimon Proctor Jan 22 '19 at 17:06
  • What you probably want is a Role for your Hash that dies if a non existent key is created. Right now https://modules.perl6.org/dist/Hash::Restricted:cpan:ELIZABETH Hash::Restricted would work if you aren't planning on modifying the Hash. – Scimon Proctor Jan 22 '19 at 17:09
  • @Scimon please see the clarification, I've shown the perl5 that I want to emulate in Perl6 – con Jan 22 '19 at 17:18
  • 1
    That's not dying though. It's giving a warning. And the warning isn't about the fact the key doesn't exist it's about using the returned undefined value in the string interpolation. – Scimon Proctor Jan 22 '19 at 17:23
  • Note if in perl6 you call say "%key"; you get basically the same error. Anyway if you really want it to die feel free to use the KeyRequired role :) – Scimon Proctor Jan 22 '19 at 17:28

4 Answers4

13

Aiui your question is:

I'm looking for use autodie qw(:all) & use warnings 'FATAL' => 'all' in Raku

The equivalent of Perl's autodie in Raku

Aiui the equivalent of use autodie qw(:all) in Perl is use fatal; in Raku. This is a lexically scoped effect (at least it is in Raku).

The autodie section in the Perl-to-Raku nutshell guide explains that routines now return Failures to indicate errors.

The fatal pragma makes returning a Failure from a routine automatically throw an exception that contains the Failure. Unless you provide code that catches them, these exceptions that wrap Failures automatically die.

The equivalent of Perl's use warnings 'FATAL' in Raku

Aiui the equivalent of use warnings 'FATAL' => 'all' in Perl is CONTROL { when CX::Warn { note $_; exit 1 } } in Raku. This is a lexically scoped effect (at least it is in Raku).

CONTROL exceptions explains how these work.

CONTROL exceptions are a subset of all exceptions that are .resume'd by default -- the program stays alive by default when they're thrown.

The Raku code I've provided (which is lifted from How could I make all warnings fatal? which you linked to) instead makes CONTROL exceptions die (due to the exit routine).

Returning to your current question text:

say %key<fake_key>; # (Any)

I want the program to die in such occurrences ...

Use either Jonathan++'s answer (use put, which, unlike say, isn't trying to keep your program alive) or Scimon++'s KeyRequired answer which will make accessing of a non-existent key fatal.

... as Perl does ...

Only if you use use warnings 'FATAL' ..., just as Raku does if you use the equivalent.

... because this implies that important data is missing.

Often it implies unimportant data is missing, or even important data that you don't want defined some of the time you attempt to access it, so both Perls and Raku default to keeping your program alive and require that you tell it what you want if you want something different.

You can use the above constructs to get the precise result you want and they'll be limited to a given variable (if you use the KeyRequired role) or statement (using put instead of say) or lexical scope (using a pragma or the CONTROL block).

raiph
  • 31,607
  • 3
  • 62
  • 111
11

You can create a role to do this. A simple version would be :

role KeyRequired { 
    method AT-KEY( \key ) { 
        die "Key {key} not found" unless self.EXISTS-KEY(key); 
        nextsame; 
    } 
};

Then you create your hash with : my %key does KeyRequired; and it will die if you request a non existent key.

Scimon Proctor
  • 4,558
  • 23
  • 22
10

The simple answer is to not use say.

say %key<fake_key>;
# (Any)

put %key<fake_key>;
# Use of uninitialized value of type Any in string context.
# Methods .^name, .perl, .gist, or .say can be used to stringify it to something
# meaningful.
#   in block <unit> at <unknown file> line 1

say calls .gist which prints enough information for a human to understand what was printed.
put just tries to turn it into a Str and print that, but in this case it produces an error.

Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129
9

Perl 5 warns, not dies, in this case. Perl 6 will do the same if equivalent code is used:

my %key;
print "%key<fake_key>\n"; # Gives a warning

Or, more neatly, use put:

my %key;
put %key<fake_key>;

The put routine ("print using terminator") will stringify the value, which is what triggers the warning about use of an undefined value in string context.

By contrast, say does not stringify, but instead calls .gist on the object, and prints whatever it returns. In the case of an undefined value, the gist of it is the name of its type, wrapped in parentheses. In general, say - which uses .gist underneath - gives more information. For example, consider an array:

my @a = 1..5;
put @a;          # 1 2 3 4 5
say @a;          # [1 2 3 4 5]

Where put just joins the elements with spaces, but say represents the structure and that it's an array.

Jonathan Worthington
  • 29,104
  • 2
  • 97
  • 136
  • 1
    thanks, `put` is definitely useful, I'm surprised that I don't see it more often in the documentation. I'm looking for the perl6 equivalent of `use warnings 'FATAL' => 'all'; use autodie qw(:all);` this is close https://stackoverflow.com/questions/34747960/perl6-how-could-i-make-all-warnings-fatal but it will still miss errors – con Jan 22 '19 at 17:59