Skip to content
This repository

modifiers for defaults (||=, //= and ''=) #45

Closed
ruz opened this Issue December 28, 2011 · 31 comments

5 participants

Ruslan Zakirov Buddy Burden Chip Salzenberg Michael G. Schwern thoughtstream
Ruslan Zakirov

Hi,

I've implemented subj. Didn't expect it to be so easy. Only a few tests and no docs. Will accept this new feature for inclusion? Example from tests:

# Test that undef, 0 and '' override defaults
method echo($message = 'what?') { return $message }
is( Stuff->echo(),          'what?' );
is( Stuff->echo(undef),     undef   );  
is( Stuff->echo(''),        ''      );  
is( Stuff->echo(0),         0       );  
is( Stuff->echo('who?'),    'who?'  );  

# Test defaults modifiers
method echo_or ($message ||= 'what?') { return $message }
is( Stuff->echo_or(),          'what?' );
is( Stuff->echo_or(undef),     'what?' );
is( Stuff->echo_or(''),        'what?' );
is( Stuff->echo_or(0),         'what?' );
is( Stuff->echo_or('who?'),    'who?'  );  

method echo_dor($message //= 'what?') { return $message }
is( Stuff->echo_dor(),          'what?' );
is( Stuff->echo_dor(undef),     'what?' );
is( Stuff->echo_dor(''),        ''      );  
is( Stuff->echo_dor(0),         0       );  
is( Stuff->echo_dor('who?'),    'who?'  );  

method echo_eor($message ''= 'what?') { return $message }
is( Stuff->echo_eor(),          'what?' );
is( Stuff->echo_eor(undef),     'what?' );
is( Stuff->echo_eor(''),        'what?' );
is( Stuff->echo_eor(0),         0       );  
is( Stuff->echo_eor('who?'),    'who?'  );  
Chip Salzenberg
Collaborator

I don't like ''= as a feature, but I like ||= and I love //=.

Ruslan Zakirov

I find ''= very useful in web applications and databases. This modifier is my primary goal. I want \S= (treat space only string as no argument) as well, but I can live without it and use ''=. If ''= is not acceptable then I have to ask if patches that improve extendability are acceptable, so I can subclass module and implement custom modifiers without black magic?

Chip Salzenberg
Collaborator

I think your real desire being to treat whitespace as missing is exactly why I thought ''= was a bad idea, besides which there is no such operator as ''=. Seems like you want type checking with coercion, which should be supportable through other means.

Ruslan Zakirov

Hi,

My real desire is to treat empty string as undef and don't treat 0 as false value. Trimming strings from spaces is different thing.

Coercion may help, but it doesn't work at the moment:

perl -I lib/ -MMouse::Util::TypeConstraints -MMethod::Signatures -E 'coerce "Int" => from "Str" => via { /\S/? $: undef }; func foo(Maybe[Int] $a //= 10) { return $a }; eval {say foo($)} or print $@ foreach 11, "", 0, undef'

I don't think coercion should work automatically, instead it should be enabled explicitly by developer for every argument.

I'm ok with ''= excluded from the patch.

Buddy Burden

I see what you're trying to do with ''=, but I'm with @chipdude : I'm a little uncomfortable with inventing new operators. I think we're going to have to throw this over to @schwern for his thoughts. My vote would be to take your ||= and //= as is, and maybe try to find a way to keep the concept of ''= and just find a better syntax for it. But schwern is the final arbiter.

Michael G. Schwern
Owner

I don't think coercion is appropriate for this use. While one certainly can use coercion to do it, coercion is more about "convert X format to Y format" but you retain the same basic value. You might convert the string "2012-01-21" to a DateTime object representing "2012-01-21", but you wouldn't use coercion to convert "" to a DateTime object representing "2012-01-21". Coercion is associated with a type, defaults are associated with the use. [1]

I also agree with @barefootcoder that existing assignment operators are better than making ours up. I would be more comfortable with an extended default syntax to allow people to express when to apply the default then to try and cover it with more operators. Something like...

method foo( Str $foo has default { "bar" } when { !/\S/ } ) {
    ...
}

This reflects the "where" block we'd like to incorporate from MooseX::MS... or maybe it should just be if ...but that's another show.

In short: IMO ||= and //= are cool, ''= is not, and a more generic "apply X to the argument when Y is true" syntax would be nice.

[1] I realize there's a big split between coercion being the choice of the type author or the type user, but all parties agree that how you coerce is associated with the type.

Chip Salzenberg
Collaborator

schwern++ nailed it

Michael G. Schwern
Owner

@barefootcoder and @thoughtstream have been having a conversation about this in private email. I'm going to paste it all in here so other folks can contribute.

Michael G. Schwern
Owner

From: Damian Conway damian@conway.org
Date: Wed, 8 Aug 2012 18:51:25 +1000
Subject: Possible patch for Method::Signatures
To: barefoot@cpan.org
Cc: Michael Schwern schwern@pobox.com

[Schwern CC'd, as this is a design issue]

Hi Buddy. Hi Schwern.

I adore Method::Signatures and am now using it in nearly all my own
development...and in absolutely all my teaching.

However, I find myself endlessly frustrated by the constant need for:

func foo ($opt_arg?) {
    $opt_arg //= $DEFAULT;
    ...
}

In order to handle the cases like:

foo( $some_hash{'some_missing_key'} );

The problem, of course, is that undef sometimes means "use the default",
but the Method::Signatures default mechanism believes that only non-
existence implies defaulting.

Now, I'm the first to admit that this is completely consistent with the
Perl 6 semantics, and usually makes a lot of sense. But I still grind my
teeth with the frequent need to explicitly //= an optional argument
within the subroutine body.

Hence the attached patch.

It adds a second kind of default to Method::Signatures,
so that instead of:

func foo ($opt_arg?) {
    $opt_arg //= $DEFAULT;
    ...
}

you can just write:

func foo ($opt_arg //= $DEFAULT) {
    ...
}

I submit it for your consideration, with the full disclosure that we
have not approved such a mechanism for Perl 6. And that Larry may well
never allow it. Personally, I find it natural and obvious, but I leave the
decision entirely up to you both. >;-)

All the best,

Damian

Michael G. Schwern
Owner

From: Buddy Burden barefootcoder@gmail.com
Date: Wed, 8 Aug 2012 09:47:48 -0700
Subject: Re: Possible patch for Method::Signatures
To: Damian Conway damian@conway.org
Cc: barefoot@cpan.org, Michael Schwern schwern@pobox.com

Damian,

It adds a second kind of default to Method::Signatures,
so that instead of:

func foo ($opt_arg?) {
    $opt_arg //= $DEFAULT;
    ...
}

you can just write:

func foo ($opt_arg //= $DEFAULT) {
    ...
}

Actually, you're the second person to make this suggestion, and,
reviewing the discussion[1], it appears that we tentatively decided to
go ahead with it, and then just dropped the ball. If you have the
time, I'd love to hear your thoughts on the discussion and also the
patch[2] that Ruz submitted.

I should be able to get one of the two patches (or some combination
thereof) applied and pushed out moderately quickly once we come to
concensus.

        -- Buddy

[1] #45
[2] #46

Michael G. Schwern
Owner

From: Damian Conway damian@conway.org
Date: Thu, 9 Aug 2012 08:38:19 +1000
Subject: Re: Possible patch for Method::Signatures
To: Buddy Burden barefootcoder@gmail.com
Cc: Michael Schwern schwern@pobox.com

Thanks, Buddy.

I agree with you and Schwern and chipdude:

//=   - yes
||=   - maybe
''=   - a step too far (no new operators!)

Actually, I worry that even ||= is a step too far: as it's more familiar
to most people and as it has previously been (mis)used for defaulting, I
think it's fraught with some peril. Perl has traditionally treated
non-existence
or undefinedness as its "default me now, baby" signals, for good reasons.
Defaulting on defined (i.e. in-band) values is a risky proposition, I think.
That's why I only suggested //= in my own patch.

I also agree with Schwern that the prospect of four separate defaulting
syntaxes means that we really need a smart-matched metasyntax.

As for the patches themselves, I think my own is slightly cleaner,
more appropriately modest in its ambitions, and has a better test suite.
But then, I would think that, wouldn't I? ;-)

I'd be completely fine with using Ruz's instead,
but only if the ||= and ''= were removed,
and you used my test suite.

Damian
.

Michael G. Schwern
Owner

From: Buddy Burden barefootcoder@gmail.com
Date: Wed, 8 Aug 2012 22:48:36 -0700
Subject: Re: Possible patch for Method::Signatures
To: Damian Conway damian@conway.org
Cc: Michael Schwern schwern@pobox.com

Damian,

Thanks for the cogent analysis!

Actually, I worry that even ||= is a step too far: as it's more familiar
to most people and as it has previously been (mis)used for defaulting, I
think it's fraught with some peril. Perl has traditionally treated
non-existence
or undefinedness as its "default me now, baby" signals, for good reasons.
Defaulting on defined (i.e. in-band) values is a risky proposition, I think.

Well, my only counter to that is that ||= already has a pretty
well-defined meaning, so people who use it really oughtn't be
surprised by its action, especially if the only reason they even know
it exists is because they read it in the POD right underneath where we
explain what //= means. ;-> But your point is well-reasoned, and I
don't really have a horse in this race--so far I've needed neither.

As for the patches themselves, I think my own is slightly cleaner,
more appropriately modest in its ambitions, and has a better test suite.
But then, I would think that, wouldn't I? ;-)

So my proposal would be to take your patch, apply it, and let's leave
it there and see if Ruz can live with that.

func foo ($fred = 42) { say $fred }
func bar ($fred //= 42 { say $fred }

foo();         # 42
bar();         # 42

my $x;
foo($x);              # uninitialized warning
bar($x);              # 42
bar($x || undef);  # just like ||= !

I'll see if schwern wants to chime in to agree or disagree.

Say, while I have your attention, mind if I ask your opinion on
another MS matter, since you seem to be a heavy MS user? What do you
think this should mean?

method foo {}

'Cause I've noticed that this is another discrepancy between MS/MSM
and MXMS. That is, we think it should mean:

method foo () {}

whereas mst and Florian and the rest of the Moosites seem to think it
should mean:

method foo (@_) {}  # not that MXMS actually supports this syntax,

but you know what I mean

And, after using MS (and especially MSM) in some real code for a while
now, I'm starting to lean towards their way of thinking. Especially
when I'm wrapping internal methods (e.g. BUILDARGS in Moose, or
usage_error in MooseX::App::Cmd), sometimes I don't have a very clear
idea just what the heck they're passing in, and I always end up
blowing up with the "too many args" error.

What's your opinion on this?

        -- Buddy

.

Michael G. Schwern
Owner

From: Damian Conway damian@conway.org
Date: Thu, 9 Aug 2012 19:01:27 +1000
Subject: Re: Possible patch for Method::Signatures
To: Buddy Burden barefootcoder@gmail.com
Cc: Michael Schwern schwern@pobox.com

Hi Buddy,

Well, my only counter to that is that ||= already has a pretty
well-defined meaning, so people who use it really oughtn't be
surprised by its action, especially if the only reason they even know
it exists is because they read it in the POD right underneath where we
explain what //= means. ;->

Fair point. Except that hasn't stopped generations of Perl programmers
misusing it to date (which is why we invented //= in the first place ;-)

So my proposal would be to take your patch, apply it, and let's leave
it there and see if Ruz can live with that.

Well, I'm certainly not going to disagree with that course of action! :-)
I suspect Ruz will not be content.

So...that got me thinking (and hence coding)...

Why should my construct be accepted, but not Ruz's.
Maybe my special case isn't special enough either.
Or maybe it's too special.
Maybe we don't need //= either.

Because maybe we can just have:

sub foo ($arg = 'default')               # existence test
sub foo ($arg = 'default' when undef)    # default if $arg ~~ undef
sub foo ($arg = 'default' when '')       # default if $arg ~~ ''
sub foo ($arg = 'default' when 0)        # default if $arg ~~ 0
sub foo ($arg = 'default' when * < 0 )   # default if $arg < 0

That's not actually quite as convenient for my own needs, but I'd be
most happy to live with it, given that it's so much more generalizable.

Sample patch attached.
(I know, I know, now I've merely made the original decision harder ;-)

I'll see if schwern wants to chime in to agree or disagree.

I'd certainly like to hear his views as well.

Especially about my latest "use-=-only-but-add-smartmatching"
alternative.

Say, while I have your attention, mind if I ask your opinion on
another MS matter, since you seem to be a heavy MS user? What do you
think this should mean?

method foo {}

Well, I would start from the philosophical position that MS should
mirror Perl 6 as far as is sensible in Perl 5. Unfortunately, in Perl 6,
no argument list means either:

method foo () {...}

or:

method foo (@_) {...}

depending on whether @_ is referred to within the subroutine body.

So that's no help. %-(

Personally, if it can't mirror Perl 6 ehaviour, then I think it should mirror
Perl 5 semantics, in which case:

method foo {...}
  func bar {...}

should mean:

method foo ($self, @_) {...}
  func bar (@_) {...}

and you'd have to say:

method foo () {...}
  func bar () {...}

to get the zero-argument forms.

So I guess I'm siding with mst and Florian and the other cervinophiles.

HTH,

Damian

Michael G. Schwern
Owner

From: Buddy Burden barefootcoder@gmail.com
Date: Thu, 9 Aug 2012 11:53:34 -0700
Subject: Re: Possible patch for Method::Signatures
To: Damian Conway damian@conway.org
Cc: Michael Schwern schwern@pobox.com

Damian,

Because maybe we can just have:

sub foo ($arg = 'default')               # existence test
sub foo ($arg = 'default' when undef)    # default if $arg ~~ undef
sub foo ($arg = 'default' when '')       # default if $arg ~~ ''
sub foo ($arg = 'default' when 0)        # default if $arg ~~ 0
sub foo ($arg = 'default' when * < 0 )   # default if $arg < 0

That's not actually quite as convenient for my own needs, but I'd be
most happy to live with it, given that it's so much more generalizable.

Well, that's very close to what schwern was thinking-out-loud in the
original discussion with Ruz, so, if you've made that work,(*) I can't
see anything to object to there. Well, except for maybe the "when * <
0" ... that one looks a little funky to me. And I suppose I would
wonder what would happen if we tried to run this on Perl prior to ~~
(pre-5.10, right?). Just wouldn't compile?

Personally, I've given up trying to run MS on pre-5.10 (or pre-5.12,
even). The whole Devel::Declare thing just gets wonky on those older
Perl's. It's the main reason I've been able to push my company into
getting off of 5.8.9 after lo these many years. (Although admittedly
that's still a work in progress.) But my point being, I personally
wouldn't have a problem having a newer version of Perl be a
requirement for MS altogether. But I think schwern doesn't want to do
that.

I'll see if schwern wants to chime in to agree or disagree.

I'd certainly like to hear his views as well.

Me too, but I think he's buried in Test::Builder stuff. At least,
that appears to be the only thing I see him raise his head for these
days. But, who knows? Maybe we'll entice him out yet. ;->

:
:
and you'd have to say:

method foo () {...}
  func bar () {...}

to get the zero-argument forms.

So I guess I'm siding with mst and Florian and the other cervinophiles.

(**) Excellent! I think I'll code up this change in a branch and see
if I can get schwern to agree to it. Maybe I'll also do a blog post
on it to see if any other MS users want to chime in.

        -- Buddy

(*) I fully admit that I haven't actually had a chance to look at your
code yet. But obviously I trust that it works.

() Heheh. "Cervinophiles" ... nice one. Although, in order to
distinguish among lovers of Bambi and fans of Santa's propulsion
system and whatnot, perhaps something more specific? Alcinophile,
perhaps? No, that would be proponents of puffins and auks ... (*
)

(***) Yes, I had to look those last two up. But Cervidae I knew ... honest! :-D

Michael G. Schwern
Owner

From: Damian Conway damian@conway.org
Date: Fri, 10 Aug 2012 11:46:18 +1000
Subject: Re: Possible patch for Method::Signatures
To: Buddy Burden barefootcoder@gmail.com
Cc: Michael Schwern schwern@pobox.com

Buddy,

Well, that's very close to what schwern was thinking-out-loud in the
original discussion with Ruz, so, if you've made that work,(*) I can't
see anything to object to there. Well, except for maybe the "when * <
0" ... that one looks a little funky to me. And I suppose I would
wonder what would happen if we tried to run this on Perl prior to ~~
(pre-5.10, right?). Just wouldn't compile?

The "when * < 0" syntax is borrowed from Perl 6, where it's a standard and
widely used feature. But I agree that it might be a little too funky for
MS. See the attached next-generation patch, which uses a Perl 5
compatible block-and-$_ syntax instead. Much more appropriate, I think.

Note that, compared to the previous submission, the attached patch also
has more robust parsing of 'when' modifiers.

Personally, I've given up trying to run MS on pre-5.10 (or pre-5.12,
even). The whole Devel::Declare thing just gets wonky on those older
Perl's. It's the main reason I've been able to push my company into
getting off of 5.8.9 after lo these many years. (Although admittedly
that's still a work in progress.) But my point being, I personally
wouldn't have a problem having a newer version of Perl be a
requirement for MS altogether. But I think schwern doesn't want to do
that.

I admire the dedication to supporting ancient Perl versions, though I
refuse to use or support them myself now. I'm confident the attached
patch isn't a problem under 5.8. The attached version now detects the
Perl you're running and reports an error if the "when..." construct is
used under 5.8 or less. It should have no ill effects so long as
5.8-users don't use the "when" feature.

I'd certainly like to hear his views as well.

Me too, but I think he's buried in Test::Builder stuff. At least,
that appears to be the only thing I see him raise his head for these
days. But, who knows? Maybe we'll entice him out yet. ;->

Fair enough. I'll keep submitting more and more outrageous patches and
you keep threatening to apply them without proper scrutiny, and I'm sure
he'll soon be forced to step in. >;-)

So I guess I'm siding with mst and Florian and the other cervinophiles.

(**) Excellent! I think I'll code up this change in a branch and see
if I can get schwern to agree to it.

I'd be all in favour of that.

(*) I fully admit that I haven't actually had a chance to look at your
code yet. But obviously I trust that it works.

Hmmmmm. Long and bitter experience indicates I'm every bit as fallible
as a real human. Better check that code. ;-)

() Heheh. "Cervinophiles" ... nice one. Although, in order to
distinguish among lovers of Bambi and fans of Santa's propulsion
system and whatnot, perhaps something more specific? Alcinophile,
perhaps? No, that would be proponents of puffins and auks ... (*
)

(***) Yes, I had to look those last two up. But Cervidae I knew ... honest! :-D

"Alces" (in classical pronunciation, at least) is very close to
"Alkies", which is our Aussie slang for "Alcoholics". So maybe the
Moose-lovers are "Elkoholics"?

Though, come to think about it, "Moose-lover"
is a pretty good epithet itself. ;-)

Damian

Michael G. Schwern
Owner

From: Buddy Burden barefootcoder@gmail.com
Date: Fri, 10 Aug 2012 13:13:19 -0700
Subject: Re: Possible patch for Method::Signatures
To: Damian Conway damian@conway.org
Cc: Michael Schwern schwern@pobox.com

Damian,

The "when * < 0" syntax is borrowed from Perl 6, where it's a standard and
widely used feature.

Oh. Well, that's ... nice. I'm sure that, you know, in the proper context ....

But I agree that it might be a little too funky for
MS.

Whew! :-D

Yeah, while generally I love doing little things in my code that
prepare me for a theoretical transition to Perl 6 one day (I'm
actually very fond of some of your own modules for that, such as
Perl6::Slurp and Perl6::Form), I do think that, in the end, it's a
different language, and I'm not sure that there are some things which
are going to work well in a Perl 5 context. I've been very pleased to
see some things backported (e.g. ~~, given/when, etc), and I actually
hope to see a few more (==> and <==, especially, if those are still
the appropriate operators in the P6 spec), but then there are some
things which I'm a little more leery of. This one I hadn't actually
seen before (or else I have and I just blocked it out of my mind :D ),
but it struck me as odd.(*)

See the attached next-generation patch, which uses a Perl 5
compatible block-and-$_ syntax instead. Much more appropriate, I think.

Rock on.

I'm confident the attached
patch isn't a problem under 5.8. The attached version now detects the
Perl you're running and reports an error if the "when..." construct is
used under 5.8 or less. It should have no ill effects so long as
5.8-users don't use the "when" feature.

Excellent!

I'd certainly like to hear his views as well.

Me too, but I think he's buried in Test::Builder stuff. At least,
that appears to be the only thing I see him raise his head for these
days. But, who knows? Maybe we'll entice him out yet. ;->

Fair enough. I'll keep submitting more and more outrageous patches and
you keep threatening to apply them without proper scrutiny, and I'm sure
he'll soon be forced to step in. >;-)

There ya go. ;->

(*) I fully admit that I haven't actually had a chance to look at your
code yet. But obviously I trust that it works.

Hmmmmm. Long and bitter experience indicates I'm every bit as fallible
as a real human. Better check that code. ;-)

Oh, yes, definitely. I just meant that, given my experience with your
work, I didn't feel the need to scrutinize the code before discussing
it. Reputation has to be good for something, no? :-)

But, yeah, before I go willy-nilly applying it, I'll dig in and give
it a critical eye. Oh, no ... wait ... I mean, no, I'm just going to
slap it in there without even looking! (Think that worked? ;-> )

"Alces" (in classical pronunciation, at least) is very close to
"Alkies", which is our Aussie slang for "Alcoholics". So maybe the
Moose-lovers are "Elkoholics"?

Oooh, that's a nice one as well. Especially since my understanding is
that what we Americans call a moose is referred to as an elk in
Europe. I'll have to steal that one. ;->

        -- Buddy

(*) So I guess this is an application of * as the "whatever" operator?
So * in P6 is multiplication, flattening, regex quantifier,
"whatever," and isn't it also involved in the hyper operations
somehow? A lot of semantic overloading on the poor asterisk ...

Michael G. Schwern
Owner

From: Damian Conway damian@conway.org
Date: Sat, 11 Aug 2012 12:29:08 +1000
Subject: Re: Possible patch for Method::Signatures
To: Buddy Burden barefootcoder@gmail.com
Cc: Michael Schwern schwern@pobox.com

(*) So I guess this is an application of * as the "whatever" operator?

Yes.

So * in P6 is multiplication, flattening, regex quantifier,
"whatever," and isn't it also involved in the hyper operations
somehow?

Yes to all, except the hyperoperations.
Also, it's the "globally scoped" twigil (e.g. $*ARGS, %*ENV, etc.)

A lot of semantic overloading on the poor asterisk ...

Hey, at least it no longer has to be the typeglob sigil! ;-)

One of our main problems in designing Perl 6 was the paucity of ASCII symbolic
characters with which to specify the dozens of new features we wanted to
add. The result is that most of them end up doing double-, triple-, or
occasionally
even more duties. Even if we discount regex meanings and twigils, all of the
following still have multiple meanings in Perl 6: ~ + % & * = [] {} ; : <> /

On the other hand, most of those have multiple meanings in Perl 5 too.
So maybe it's a case of the pot calling the kettle "confusing". ;-)

Moreover, in designing Perl 6, we tried very hard to make the multiple
meanings either consistent (like ~ being binary concatenate-strings and
unary coerce-to-string and + being binary add-numbers and unary
coerce-to-number), or else consistent with existing Perl 5 (ab)usage.

Sure your can find bad edge-cases:

my $multiplier = * * *;

but you can do worse in Perl 5:

my $zero_value = <=> <=> <=>;

;-)

Meanwhile, on an unrelated topic: the one other thing that really bugs
me about the current interface of MS compared to that of Perl 6 or MXMS
is the inability to specify of type constraints via 'where' modifiers within
the signature.

The introduction of 'when' modifiers would make this a little more
tricky to implement robustly, but if (in a week or two) I sent you a
patch for 'where' constraints, would you consider it?

Damian

Michael G. Schwern
Owner

Sorry to @barefootcoder and @thoughtstream (who is Damian if folks didn't know) for having that all repeated in their inbox. Now everyone is up to speed and can participate. @thoughtstream, if you're not comfortable with submitting patches as pull requests, you can "attach" them by pasting them into http://gist.github.com and putting the link in here (unless the Github Issues email gateway does something REALLY clever with email attachments).

Several issues have gotten mixed up in here, so I want to tease them apart. This issue is already complicated and I want to shunt these off to their own issues.

First, what should a method with no signature do? We discussed this before, so might as well reopen that one. #26

The when syntax IMO needs more discussion. Also it should be considered separately from //=. //= is a clear win and slides easily into the existing default syntax. when has parsing edge cases, a default is any valid expression. I've cracked open a new issue for that, please discuss it there. #48

Ok, so... yes to ||= and //=. I hear Damian's argument about ||= being abused a lot. I don't really know if I agree with it, but we don't have the data. What I do agree with is that //= is the far more useful operator. That's the one I care about seeing. If ||= is implemented as well, I don't see any real harm. If it's not, it can be added later. So I say leave that up to the implementer.

As to whose implementation should win, now @ruz and @thoughtstream can collaborate if they want to. Otherwise, take the first complete patch and fix it up if necessary.

thoughtstream
Collaborator

I'm eager to discuss the semantics of missing signatures but
#26
has not been reopened yet.

thoughtstream
Collaborator

I note the new thread for discussing when, but I think some of that discussion
belongs here as well.

The reason I suggested when modifiers instead of //= and ||=
is that I belive it's a much more momentous decision to move from a single
default indicator to two (or three). Especially when that move encourages
people to suggest ''= as well!

The when proposal covers all those cases (and infinitely more cases besides)
without multiplying entities unnecessarily. Yes, it has parsing issues, but I do not
think they are insurmountable. And, given that Method::Signatures already uses PPI,
we might well deploy that module to handle the hard cases here as well.

In Perl 6, we (have so far) resisted //= as an argument default marker,
and I wonder whether, in Perl 5, we shouldn't perhaps resist it too?

Michael G. Schwern
Owner

The parsing issues can be overcome, I'm sure. ||= and //= are syntax conveniences for the two most common defaults. They're simpler and shorter to express, but more importantly, they're existing Perl 5 assignment operators. The answer to, "how do I write the equivalent of $arg //= 42" is "$arg //= 42" not "$arg = 42 when undef" which is a new kind of statement modifier we just made up.

Other than the // and || cases, I don't see a general purpose default condition being used very often. Make generic conditions possible, but make the most common version as convenient and obvious as possible.

I don't see how having only one default assignment operator is worth making the user use a statement modifier we just made up. I also don't see why having only one default assignment operator is valuable, aside from some vague language principles.

thoughtstream
Collaborator

Err...you keep saying that when COND is something "we just made up",
but it isn't. Postfix when is a standard feature of Perl (from Perl 5.14).
As described in http://perldoc.perl.org/perlsyn.html#Switch-Statements.

As for the general purpose default condition not being used very often,
Ruz already gave an excellent use-case for when ''. And I think I could
make a pretty solid argument for = 1 when { $_ <= 0 },
which I seem to need all the time.

Finally, the language principles here are not "vague"; they are very clear:
Having one way to do something (i.e. specify a default with =) is easy to teach;
Having three ways (= vs //= vs ||=) is considerably harder to teach.
Especially when one of those three ways is usually a mistake, and the other
two are diametrically opposite in effect, depending on what undef means to you.

Moreover, having three defaulting indicators introduces the requirement to make
a choice every time, which is never a good thing.

Moreoverer, I worry that those three are the thin edge of the stiletto:
if we have three defaulting operators, why not four, or five, or twenty?

Personally, I think one default marker (=) and one default modifier (when COND)
is the right balance. I'd be okay with = plus //= plus when COND, and would
grit my teeth manfully and swallow = plus //= plus ||= plus when COND,
if I must.

And I guess that would, at least, give me something new to proscribe in PBPv2. ;-)

Buddy Burden
Owner

While I agree with @thoughtstream on most of his points, I'm not sure I agree that it would be harder to teach. If I were teaching it, I would teach the when first, and then just explain that //= was a convenient shortcut for when undef. Trez TMTOWTDI. If when undef is the most common case, why not have a shortcut for it? Particularly one which seems blatantly obvious on the face of it what it does.

I do agree that ||= might be a bridge too far though. One shortcut is convenient. Two, three, or a dozen can get confusing. So my vote is: keep the when, keep the //=, lose the rest.

But I'm willing to be convinced otherwise. :-)

thoughtstream
Collaborator

So my vote is: keep the when, keep the //=, lose the rest.

Seconded.

I'll implement the next version of the patch along those lines,
and we can wait to see what consensus emerges and then
prune or extend it as necessary.

Ruslan Zakirov
ruz commented August 13, 2012
thoughtstream
Collaborator

[Ignore the following. It doesn't make sense. See the next two comments for details.]
[And remember, boys and girls, don't post comments more than three hours after your normal bedtime!]

I can not think of a good example, but believe that it
may be useful to know inside CODE whether argument
is provided or not.

A very good point.

Currently the plan is that, within a when test, the argument that
was passed to the parameter will be both aliased to $_ and also
passed directly to the when block/sub. So, an absent arg
would set $_ to undef but pass no arg to the when sub.
Which means you could test whether the argument was passed
or not, by testing !@_ within the when block.

For example:

# undef is a valid setting for the error handler,
# but a missing argument is not (this is tested by: !@_)
# and a regex is not either (this is tested by: ref eq 'Regexp')...

func set_error_handler (
$handler = $DEF_HANDLER when { !@_ || ref eq 'Regexp' }
) {...}

Nope. The use of a nested @_ is just too fugly and confusing
(and it just feels wrong too).

So maybe a missing argument is indicated by aliasing (and passing)
a special object that is blessed into a hightly distinctive and descriptive
class. Like so:

# undef is a valid setting for the error handler,
# but a missing argument is not (this is tested by: ref eq 'NO ARG')
# and a regex is not either (this is tested by: ref eq 'Regexp')...

func set_error_handler (
$handler = $DEF_HANDLER when { ref ~~ ['NO ARG', 'Regexp' ] }
) {...}

Hmmmm. I'll code that into the patch and see how it feels.
'NO ARG' seems like a pretty safe class name to use; it's
very unlikely anyone is going to be using that as a real class
name in their code.

Buddy Burden
Owner

Wait, a default value which isn't supposed to apply when the argument isn't passed? You guys are going to have to come up with a reasonable use case before I agree that that's a good idea ...

Not to be harsh or anything; I'd just like to know that this is not a solution in search of a problem before anyone spends any time on it.

thoughtstream
Collaborator

Fear not, @barefootcoder, no-one is suggesting that defaults could ever be skipped
if the arg isn't passed.

I was just not thinking straight (because I was thinking late) and didn't realize that
@ruz's edge-case can't exist.

The proposal is still that a when modifier is only checked if the argument was
actually passed. If no argument was passed, the default is always applied,
without bothering to test the when criterion.

That means that, if you end up executing the block of a when CODE test
and $_ is undefined, an actual undef must have been passed. If no argument
had been passed, the default would have been applied automatically and unconditionally,
so the when's block wouldn't have executed at all.

I've now struck out the previous comment to emphasize that.
Sorry for the confusion.

Buddy Burden
Owner

The proposal is still that a when modifier is only checked if the argument was actually passed. If no argument was passed, the default is always applied, without bothering to test the when criterion.

Okay, that makes a lot more sense. :-) I'm glad that's the case, because I really wasn't seeing how it made sense the other way. ;->

Michael G. Schwern
Owner

@thoughtstream Sorry, I didn't know that postfix when is a Perl 5 feature! That makes me happier.

I don't think the teaching issue is a simple number of assignment operators so long as we're talking about existing and commonly used assignment operators. But as I've said before, when and blah= are separate issues in my mind.

The behavior of when if nothing is passed in (ie. it acts like a normal default) seems sensible.

Buddy Burden barefootcoder closed this December 02, 2012
Buddy Burden

Fixed in version 20121201.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.