locked_user sundialsvc4 has asked for the wisdom of the Perl Monks concerning the following question:

There are certain attributes in my classes for which I would like to generically specify that “assigning undef to these attributes should instead set them to an empty-string.”  I know how to do this with an around modifier for the (list of) accessors, but it seems to me that there should be a more-clever way to do that.   Is there any kind of trait or role or what-have-you that will let me specify this behavior on a per-attribute basis?

Here is “clunky code” to do what I want:   (with the wantarray bit being unimportant; see #MAGICK HERE for the exact spell I want to cast)

around [qw(attr1 attr2 attr3)] => sub { my $orig = shift; my $self = shift; if (wantarray) { my @array_result = $self->$orig(@_); return @array_result; } else { my $scalar_result = $self->$orig(@_); $scalar_result = '' unless defined($scalar_result); #MAGICK HERE return $scalar_result; } };

Notice incidentally that this code actually allows an undef to be stored but presents an empty-string as the result of either a getter or a setter.   The exact details are perhaps less important than the notion that I would like to be able to apply behaviors like this to around several accessors (regardless of their names).   Without writing clunky code for each one.   It just seems to me that there ought to be a very clever way to do this ...


UPDATE:   As the following threads will show, my initial guesses that a type-constraint and type-coercion ought to be the solution ... were correct.   But I overlooked the necessity of telling Moose to actually do the coercion.   (And, yeah, the documentation to that effect.)   “So now, Gentle Reader, you know.”   Meanwhile, read on . . .

Replies are listed 'Best First'.
Re: Moose trait (?) to set "undef" to, say, "empty string?"
by ikegami (Patriarch) on Nov 29, 2011 at 04:04 UTC

    Create a type that's a subtype of Str. For that type, create a coercion rule so that Undef is coerced to the empty string. Use that type and coerce=>1 for the attribute.

    use Moose::Util::TypeConstraints; subtype 'MyStr', as 'Str'; coerce 'MyStr', from 'Undef', via { '' }; no Moose::Util::TypeConstraints; has foo => ( isa => 'MyStr', coerce => 1, ... );

    Can't think of a good name for it.

Re: Moose trait (?) to set "undef" to, say, "empty string?"
by locked_user sundialsvc4 (Abbot) on Nov 29, 2011 at 13:27 UTC

    Weird.   I tried that.   Didn’t work.   The coercion never got called.   (Pardon me, don’t take this wrongly...)   Did you actually try the code that you posted here?   (I will be delighted if the answer is, “yes.”)

    Hmmmm....   Note that I did not (yet...) try specifying coerce=>1.   Is that the magick?

      If by magick you mean the well documented way in which coercions work, the answer is yes. :\

      Moose::Manual::Types: Moose will never try to coerce a value unless you explicitly ask for it. This is done by setting the coerce attribute option to a true value...
      Moose::Cookbook::Basics::Recipe5: However, defining the coercion doesn't do anything until we tell Moose we want a particular attribute to be coerced...
      Moose: coerce => (1|0) This will attempt to use coercion with the supplied type constraint to change the value passed into any accessors or constructors. You must supply a type constraint, and that type constraint must define a coercion...

      See also, Moose::Manual::FAQ and probably other spots.

        Must be getting too old for this ...   I guessed (correctly) that it had to do with type-constraints and with coercions, but simply overlooked the importance of that flag.   I guess I decided too-quickly that maybe it was looking for a particular type-definition and not matching the coercion specification, instead of not attempting any coercion at all.   Merely specifying a coerce rule doesn’t cause it to be invoked.   Sigh.   Shows what ’ya get sometimes, for chasin’ them red herrings and jumpin’ to conclusions ...

        Thank you, sincerely, for pointing out these documentation references to me.

      No, I didn't try that code specifically, but I have done coercions many times before. Yes, it won't perform coercion without coerce=>1. Couldn't you look it up instead of asking me that?

        Oh, sure ... it’s just that I feel so ... 8~<:*} ... stoopid to have been so close to the right answer and yet to have missed it... (swish!!)   Hope you’re not (seriously) offended.   Mea culpa.

        Thank you, in all seriousness, for your valuable assistance.   Upvoted.

Re: Moose trait (?) to set "undef" to, say, "empty string?"
by Anonymous Monk on Nov 30, 2011 at 03:16 UTC

    To close this thread (for you, Gentle Reader, who have stumbled upon it since ...) a type-coercion did, indeed, solve the problem perfectly.   The “magick,” that I indeed had overlooked, is that the mere mention of a coerce rule is not by itself sufficient to actually cause that coercion rule to be invoked.   (Documented, yes.   “Counter-intuitive, perhaps,” also very-definitely yes.)   I am indeed sincerely grateful and appreciative for the help ... momentarily embarrassing :*) though it turned out to be.

      Oh, fudge... yeah, “that was me.”   Perlmonks logged me out.