autodie::hints(3perl)

πŸ’– autodie::hints πŸ’–

okay bestie, welcome to the autodie::hints page from the 3perl manual (Perl Programmers Reference Guide, she's a legend). this is where you teach autodie how to read your subs' minds 🧠✨ let's GO

✨ NAME ✨

autodie::hints β€” Provide hints about user subroutines to autodie

πŸŽ€ SYNOPSIS πŸŽ€

package Your::Module;

our %DOES = ( 'autodie::hints::provider' => 1 );

sub AUTODIE_HINTS {
    return {
        foo => { scalar => HINTS, list => SOME_HINTS },
        bar => { scalar => HINTS, list => MORE_HINTS },
    }
}

# Later, in your main program...

use Your::Module qw(foo bar);
use autodie      qw(:default foo bar);

foo();         # succeeds or dies based on scalar hints

# Alternatively, hints can be set on subroutines we've
# imported.

use autodie::hints;
use Some::Module qw(think_positive);

BEGIN {
    autodie::hints->set_hints_for(
        \&think_positive,
        {
            fail => sub { $_[0] <= 0 }
        }
    )
}
use autodie qw(think_positive);

think_positive(...);    # Returns positive or dies.

πŸ¦‹ DESCRIPTION πŸ¦‹

🌸 Introduction 🌸

so like, the autodie pragma is genuinely SO smart when it comes to Perl's built-in functions πŸ’… the behaviour for those built-ins is fixed, and autodie knows exactly how they try to signal failure. no guessing, no vibes, she just knows.

but what about user-defined subroutines from modules?? πŸ™ˆ here's the thing: if you use autodie on a user-defined subroutine, it just assumes these things mean failure:

  • A false value, in scalar context
  • An empty list, in list context
  • A list containing a single undef, in list context

and literally every other return value is treated as a win πŸŽ‰ β€” including the list of the single zero, and the list containing a single empty string.

but bestie. real-world code is not always that easy 😭 maybe the code you're working with returns a string containing the word "FAIL" when it fails, or a two element list containing (undef, "human error message"). that's... not the default pattern at all. and that is EXACTLY why the hinting interface exists, periodt.

the hinting interface lets you hand autodie hints about how it should detect failure from user-defined subroutines ✨ and while the end-user of autodie can provide these, the ideal situation β€” the dream, the main character move πŸ‘‘ β€” is for them to be written into the module itself, or into a helper module or a sub-class of autodie itself.

πŸ’œ What are hints? πŸ’œ

a hint is a subroutine or a value that gets checked against the return value of an autodying subroutine. if the match comes back true, autodie decides the subroutine failed πŸ’€ that's it, that's the whole mechanic.

here's the breakdown of what a hint can be:

  • if the hint is a subroutine, then autodie passes the complete return value to that subroutine.
  • if the hint is a regexp object, then autodie matches it against the return value.
  • if the hint is undef, the return value must be undef.
  • on Perl versions 5.10 and newer, any other value can be provided and it will be smart matched against the value provided.
⚠️ heads up bestie β€” smart matched values like this are deprecated. so like, don't build your whole personality around them, ok? πŸ™ˆ

hints can be provided for both scalar and list contexts 🫢

and one more thing that's lowkey important: an autodying subroutine will never see a void context, because autodie always needs to capture the return value for examination. so when an autodying subroutine gets called in void context, it acts as if it's called in a scalar context β€” but its return value gets discarded after it's been checked. bye bye return value πŸ‘‹

🧚 Example hints 🧚

hints may consist of subroutine references, objects overloading smart-match, regular expressions, and depending on your Perl version possibly other things too ✨ and yes, you can specify different hints for how failure should be identified in scalar vs list contexts. slay.

these examples apply for use in the AUTODIE_HINTS subroutine and when calling autodie::hints->set_hints_for().

the most common context-specific hints are:

# Scalar failures always return undef:
    {  scalar => sub { !defined($_[0]) }  }

# Scalar failures return any false value [default expectation]:
    {  scalar => sub { ! $_[0] }  }

# Scalar failures always return zero explicitly:
    {  scalar => sub { defined($_[0]) && $_[0] eq '0' }  }

# List failures always return an empty list:
    {  list => sub { !@_ }  }

# List failures return () or (undef) [default expectation]:
    {  list => sub { ! @_ || @_ == 1 && !defined $_[0] }  }

# List failures return () or a single false value:
    {  list => sub { ! @_ || @_ == 1 && !$_[0] }  }

# List failures return (undef, "some string")
    {  list => sub { @_ == 2 && !defined $_[0] }  }

# Unsuccessful foo() returns 'FAIL' or '_FAIL' in scalar context,
#                    returns (-1) in list context...
autodie::hints->set_hints_for(
    \&foo,
    {
        scalar => qr/^ _? FAIL $/xms,
        list   => sub { @_ == 1 && $_[0] eq -1 },
    }
);

# Unsuccessful foo() returns 0 in all contexts...
autodie::hints->set_hints_for(
    \&foo,
    {
        scalar => sub { defined($_[0]) && $_[0] == 0 },
        list   => sub { @_ == 1 && defined($_[0]) && $_[0] == 0 },
    }
);

okay so that "in all contexts" construction? it's super common, and you can abbreviate the whole thing using the 'fail' key πŸŽ€ this sets both the "scalar" and "list" hints to the same value:

# Unsuccessful foo() returns 0 in all contexts...
autodie::hints->set_hints_for(
    \&foo,
    {
        fail => sub { @_ == 1 and defined $_[0] and $_[0] == 0 }
    }
);

# Unsuccessful think_positive() returns negative number on failure...
autodie::hints->set_hints_for(
    \&think_positive,
    {
        fail => sub { $_[0] < 0 }
    }
);

# Unsuccessful my_system() returns non-zero on failure...
autodie::hints->set_hints_for(
    \&my_system,
    {
        fail => sub { $_[0] != 0 }
    }
);

πŸ’… Manually setting hints from within your program πŸ’…

so if you're using a module that returns something special on failure, you can manually create hints for each of the subroutines you want 🫢 and here's the cute part: once the hints are specified, they're available for all files and modules loaded thereafter β€” which means you can move this work into a module and it'll still work. it's giving "set it and forget it" energy ⭐

use Some::Module qw(foo bar);
use autodie::hints;

autodie::hints->set_hints_for(
        \&foo,
        {
                scalar => SCALAR_HINT,
                list   => LIST_HINT,
        }
);
autodie::hints->set_hints_for(
        \&bar,
        { fail => SOME_HINT, }
);

now, you can pass either a subroutine reference (recommended!! πŸ’–) or a fully qualified subroutine name as the first argument. which means you can set hints on modules that might get loaded later:

use autodie::hints;
autodie::hints->set_hints_for(
        'Some::Module:bar', { fail => SCALAR_HINT, }
);

this technique is most useful when you've got a project that uses a whole lot of third-party modules. you can define every possible hint in one place β€” one spot, one vibe β€” and honestly it can even live in a sub-class of autodie. like:

package my::autodie;

use parent qw(autodie);
use autodie::hints;

autodie::hints->set_hints_for(...);

1;

and now you can just use my::autodie πŸŽ‰ which works exactly like the standard autodie, except she's now aware of every hint you've set. iconic behaviour, no notes.


🌈 Adding hints to your module 🌈

autodie provides a passive interface to let you declare hints for your module 🌸 these hints will be found and used by autodie if it's loaded β€” but otherwise they have no effect (and no dependencies!) without autodie. so chill.

to set them, your module needs to declare that it does the "autodie::hints::provider" role. you've got options bestie:

  • write your own "DOES" method,
  • use a system such as "Class::DOES" to handle the heavy-lifting for you, or
  • declare a %DOES package variable with a "autodie::hints::provider" key and a corresponding true value.
πŸ“Œ note that checking for a %DOES hash is an "autodie"-only short-cut. other modules do not use this mechanism for checking roles β€” though you can absolutely use the "Class::DOES" module from the CPAN to allow it, if that's your vibe.

on top of that, you must define an "AUTODIE_HINTS" subroutine that returns a hash-reference containing the hints for your subroutines:

package Your::Module;

# We can use the Class::DOES from the CPAN to declare adherence
# to a role.

use Class::DOES 'autodie::hints::provider' => 1;

# Alternatively, we can declare the role in %DOES.  Note that
# this is an autodie specific optimisation, although Class::DOES
# can be used to promote this to a true role declaration.

our %DOES = ( 'autodie::hints::provider' => 1 );

# Finally, we must define the hints themselves.

sub AUTODIE_HINTS {
    return {
        foo => { scalar => HINTS, list => SOME_HINTS },
        bar => { scalar => HINTS, list => MORE_HINTS },
        baz => { fail => HINTS },
    }
}

this lets your code set hints without relying on "autodie" and "autodie::hints" being loaded β€” or even installed πŸ¦‹ and that's the whole point: your code can do the right thing when "autodie" is installed, but it does not need to depend upon it to function. flexible. unbothered. thriving. πŸ‘‘

⭐ (more coming in part 2...)

πŸ’… insisting on hints πŸ’…

okay so here's the tea, bestie: when a user-defined subroutine gets wrapped by autodie, it will use hints if they're there, and if they're not it just falls back to the default behaviour described in the intro of this doc. which sounds fine until it isn't β€” it gets real problematic if you expect a hint to exist but, for whatever reason, it lowkey never got loaded. πŸ’€

so the fix? you can tell autodie to insist that a hint gets used by slapping an exclamation mark at the front of the subroutine name. and a lone exclamation mark means "every subroutine after this one has to have hints declared." periodt. πŸ‘‘

# foo() and bar() must have their hints defined
use autodie qw( !foo !bar baz );

# Everything must have hints (recommended).
use autodie qw( ! foo bar baz );

# bar() and baz() must have their hints defined
use autodie qw( foo ! bar baz );

# Enable autodie for all of Perl's supported built-ins,
# as well as for foo(), bar() and baz().  Everything must
# have hints.
use autodie qw( ! :all foo bar baz );

and if hints aren't available for the subroutines you named? that's a compile-time error, no cap. 😭 tho the good news: insisting on hints for Perl's built-in functions (like open and close) is always successful. πŸŽ€

insisting on hints is strongly recommended. like, do it. it's giving responsible main character. ✨

🩺 Diagnostics 🩺

  • Attempts to set_hints_for unidentifiable subroutine β€” so you called autodie::hints->set_hints_for() with a subroutine reference, but that ref could not be resolved back into a subroutine name. πŸ˜΅β€πŸ’« maybe it's an anonymous subroutine (which literally cannot be made autodying), or it just lacks a name for other reasons.

but if you're getting this error for a subroutine that does have a real name? then bestie, you may have found a bug in autodie. go look at "BUGS" in autodie for how to report it. πŸ›

  • fail hints cannot be provided with either scalar or list hints for %s β€” when you're defining hints you get two vibes of choice: supply both the list and scalar keywords, or supply a single fail keyword. that's it. you cannot mix and match them, that's not the vibe. πŸ™…β€β™€οΈ
  • %s hint missing for %s β€” you gave a scalar hint without supplying a list hint, or the other way round. you have to hand over both scalar and list hints, or just a single fail hint. all or nothing, babe. πŸ’…

🌸 ACKNOWLEDGEMENTS 🌸

  • Dr Damian Conway for suggesting the hinting interface and providing the example usage. πŸ‘‘
  • Jacinta Richardson for translating much of my ideas into this documentation. 🫢

πŸ’– AUTHOR πŸ’–

Copyright 2009, Paul Fenwick <pjf@perltraining.com.au>


⭐ LICENSE ⭐

This module is free software. You may distribute it under the same terms as Perl itself.


🌈 SEE ALSO 🌈

  • autodie
  • Class::DOES

and that's a wrap on this page, bestie!! πŸŽ€βœ¨ this was perl v5.44.0, dated 2026-10-17 β€” autodie::hints(3perl) β€” go forth and hint responsibly πŸ¦‹πŸ’œπŸ’…

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms