This comes up when an interface takes a pattern to match things against. Sometimes you have some reason to want this match to always fail, so you want to pass a pattern which will never match. The customary way of doing this is to pass qr/(?!)/
. There is a problem with that, though.
I’m not talking here about the fact that if possible, you really don’t want to pass an actual qr
object. We’ve already covered that. It was a surprising enough discovery that I’ll take this opportunity to signal-boost that while we’re here, but this article is not about that.
/(?!)/
is O(n). Yes! Exactly! I was just looking at an example of this pattern in some code I’m working on and had a scales-off-my-eyes moment. Indeed this is borne out by some quick benchmarking; something like this:
use Benchmark::Dumb 'cmpthese'; # check this out if you haven't
my $iter = 100;
my $len = 100000;
$::a = 'a' x $len;
cmpthese 0, {
floating => q[die if $::a =~ /(?!)/;] x $iter,
anchored => q[die if $::a =~ /\A(?!)/;] x $iter,
};
This gives me results like this:
Rate/s Precision/s floating anchored floating 5.5948 0.0019 -- -99.9% anchored 4165.1 3.9 74346.2% --
Note the disparity in rate: the anchored
version is orders of magnitude faster.
Confused about what is going on? The answer is that a pattern does not have to match at the start of the string, so if a pattern fails to match there, the regexp engine will skip one character and try again from that point. To return false, the regexp engine must exhaust the entire string in this way, attempting to match the pattern at every offset – unless the pattern is anchored, which the engine knows cannot succeed anywhere other than the start of the string. Thus, while both patterns always fail, it takes floating
as long to fail as the input string is long, i.e. O(n), whereas anchored
always fails in the same amount of time for any input string, i.e. O(1).
In fact, this goes the other way too. Because floating
is simpler, for very short strings (i.e. small n), it is faster. If I turn the $len
parameter down to 10, I get results like this:
Rate/s Precision/s anchored floating anchored 3740.8 3.1 -- -3.3% floating 3867.43 0.023 3.4% --
For a $len
of 0, I even get results like this:
Rate/s Precision/s anchored floating anchored 3730.2 3.1 -- -10.0% floating 4146.88 0.028 11.2% --
But just turning the length up to 12 is enough to consistently get me results like this:
Rate/s Precision/s floating anchored floating 3913.9 3.4 -- -5.5% anchored 4141.9 3.8 5.82+-0.13% --
So you might squeeze out a smidgen more performance by using floating
in cases where you know that input strings cannot be long and that they will often be empty. But the breakeven point on my machine is at a length of just 11, where anchored
mostly wins by a few percent but floating
occasionally beats it by hundredths of a percent (in Dumbbench precision parlance). And even in the empty-string case, the difference in absolute terms is so marginal that overall I feel this is not worth even keeping in mind.
This leaves a conveniently simple conclusion:
Use /\A(?!)/
as the always-fail pattern. Don’t use /(?!)/
.
And now we’re trapped. There’s only one
friend
variable, constantly changing as we go through the loop, with the most likely result one of our friends will get half a dozen messages, while the other five receive nothing, to the annoyance of both groups.
Funny that Perl got this one right when not only many before didn’t but many since also haven’t.
In Go, as Ted says, they may even change the language to fix it
; in Javascript, they already have.
Another possibly useful prototype is the underscore (“_
”), which allows functions to default to $_
when given no argument, like e.g. chr
and hex
do.
Buzzard, Buzzard. If you go around accusing people of not knowing the difference between empathy and sympathy, maybe you should not be making the same mistake. 🙂
]]>Even in cases when the facts, presented with no further comment, spoke for themselves (as hopefully demonstrated in this example), I found no way to point out objectively flawed but emotionally invested decision-making of this kind without triggering an emotional response. This despite my pathological capacity to keep my emotions to myself and to keep strictly to the facts in my communication. Most people do not have my peculiarities and are therefore not capable of that to anywhere near the same extent. And most cases are not going to be as clear cut. So if there were a disagreement, I cannot conceive how anyone with a legitimate concern could in any fairness be expected not to run afoul of the fragility in question.
Would I express myself the way Mighty Buzzard did, no, but I can’t… claim absence of any sympathy for his point. (Though I would disagree about jerks masquerading as emotionally fragile: a lot of them are emotionally fragile. A lot of the time, being a victim and being a bully go hand in hand; without strenuous conscious effort, people will perpetuate their own suffering in others. (Apologies for handwaving many acres of the field of psychology here; the margin of this comment box is too small.)) I am well aware that there are people who hide behind this to justify straight-up asshole behavior, and I am wary of them riding on the coattails of what concerns me. But I cannot with honesty get on board with the tone policing program.
So what then does that make of me? Should I absent myself from the community for the good of it?
]]>I almost left Perl because of Sawyer’s stewardship. And I mostly dropped out of the community because watching the giant flamewar caused by the technical decisions he intended to pursue made me miserable. The exhaustion of bracing for the worst at turn after turn in the saga, and the anticipation of dealing with the technical fallout going forward, had me actively looking for an off-ramp from Perl.
Nobody attacked me personally, though. I was miserable directly because of Sawyer – but I get no claim to abuse. Nor do I wish I did; rather, I am trying to convey the light in which I see his.
I’m sorry to say I am thankful that his departure mostly prevented the looming damage, and that I believe that taking the line he took as well as his often defiant style of personality are part of the reason for the vitriol that echoed back to him. Nevertheless I can’t say I’m happy that this ended up being how the damage was averted. I always liked Sawyer, we got on as friends when we would meet and shoot the breeze; I have no glee over his suffering. I said barely anything about my opinions on all this to him myself (or spoke up much in any public venue for that matter). That is because I had no sense that factual arguments were going to have any useful effect – which I suppose left abuse as the only resort available to whoever might have felt pushed to try anyway (as opposed to my usual response of just quietly slipping away).
Now by his own account, Sawyer received a lot of vitriol more or less for the mere fact of being the pumpking. If indeed that goes beyond backlash he (I am – see above – sorry to say) invited on himself, as he claims, then that part I find dismaying. Here too I will qualify that some small extent of this I believe that one has to expect and endure when signing up for a job such as pumpking, given that it is a public position with power that affects quite a lot of people. But as I understand Sawyer, what he experienced apparently went well beyond that. That part I have no mixed feelings about: it unequivocally should not happen.
I am sorry to say I am unsure about that too, though. I would be curious about the experience of other pumpkings. Sawyer in his talk mentioned Rafael’s deeply regrettable experience – a sordid chapter in the Perl community’s history, certainly. And yet… this does not seem to apply across the board. I wonder in what terms Ricardo would put his experience, for example.
So I don’t know what to say. I can’t claim to disagree with Mighty Buzzard here. Ultimately I am unhappy with what happened from all angles. Sawyer was not fit to be pumpking. Because he was given that role, everyone lost – himself included.
]]><code>
tag. OG Markdown does support code blocks and does render them as <pre><code>
tags – but you have to use the old-school indentation-based way to indicate them.]]>
That is the opposite of not working. 🙂 You have to use it, like you would in any plain HTML document, together with <pre>
for a block of code (as per the Notes section of that page, which for some reason I cannot link directly).
[…] Corporate-employed FOSS maintainers working at a firm with these [very common] “growth and novelty” incentives [… are] in a position where their job performance is very likely to be evaluated in terms of visible growth and novelty (it might be dressed up in more abstract terms like “real-world impact” or “visibility” but it still means the same thing) even though that is exactly the wrong thing for the health of the project they’re maintaining.
I’m excerpting the gist of his article here but actually I suggest reading all of it. It’s not very long but gives flesh to this skeleton argument.
It doesn’t help that what he is talking about isn’t limited to employed maintainers; profit is not the only growth incentive structure that can lead to this novelty mindset, so this can exist entirely outside commercial context.
]]>To my astonishment, doing the minimum-effort thing of googling for [mojocast perl] does turn up an Archive.org collection containing a sparse few of its episodes: https://archive.org/details/podcast_mojolicious-mojocasts_464926730
That is probably the best you can hope for.
]]>There is a much more important reason to avoid -w
, which is objective: it’s not at all the same thing as use warnings
. Whereas use warnings
applies to the rest of the current scope, -w
is completely global. Under -w
, any module loaded directly or indirectly will have warnings forced on it, even if the module itself does not turn on warnings – which nowadays almost certainly means it was written to run without warnings. Therefore -w
should no longer be used. At all.
We have had use warnings
since Perl 5.6 – in fact lexical warnings were one of the major changes in that version. 5.6 came out in 2000. The -w
switch is 1990s technology.