develooper Front page | perl.perl5.porters | Postings from January 2022

Re: PSC #049 2022-01-07

Thread Previous | Thread Next
From:
Tom Molesworth via perl5-porters
Date:
January 16, 2022 10:30
Subject:
Re: PSC #049 2022-01-07
Message ID:
CAGXhHdkM_qvXGdt3qazC768u4nXapa55k3vXxeG5mmOJx+xLqw@mail.gmail.com
On Sun, 16 Jan 2022 at 16:44, demerphq <demerphq@gmail.com> wrote:

> On Sun, 16 Jan 2022 at 09:12, Tom Molesworth via perl5-porters <
> perl5-porters@perl.org> wrote:
>
>> To recap the original problem: someone who learns Perl-with-signatures
>> who wants to pass a callback to a CPAN module will be writing fragile code.
>> This is something that library authors have no control over. The suggestion
>> is "library documentation should tell developers that they must always
>> include , @ in callbacks".
>>
>
> If those callbacks do not share a common signature then yes, that is what
> they must do. I dont understand why you assume that any case where
> callbacks are used will have inconsistent signatures. It seems to me that
> it is equally likely most callbacks would be the other way around. Eg,
> favoring one case or another is an arbitrary decision that comes down to
> some external factoid about the situation.
>

hmm - I think the external factoid here would be "was written for the
earlier version, before the new option was added"? There's momentary
convenience in being able to leave out the parameters without the `,@`, but
that's not really the focus. At the time the original code was written,
signatures would presumably be consistent - there's only one case, the
documented API with however many callback parameters were passed at the
time, so there's no decision or favouring involved...

From your questions here, I get the impression that perhaps you're still
not clear on exactly what type of situation is problematic? Just in case,
here's a trivial example:

Let's say we have a module X that provides `->each(sub ($item) { ... })` as
a method. Perhaps it has an array-like structure internally and allows you
to iterate over items.

As code builds up over time, such as `$obj->each(sub ($item) { say "Item:
$item" })`, everyone's happy, there may be an obscure note in the
documentation about putting in `, @` in the signature somewhere but things
work fine without that, and half the developers using this don't understand
what that meant (or didn't read it in the first place). This module starts
to occupy a key position in the CPAN dependency stream, and everyone loves
it...

... except for one unsatisfied customer who points out that this isn't
useful enough in the current state: it should also pass the index. They
raise a patch supporting their very-important usecase: `$obj->each(sub
($item, $index) { say "Item $item had index $index" })`.

Maybe all the tests already have the `,@` as advised, maybe tests are
updated to fix everything that broke... either way, that new version is
released. Anyone who upgrades and *didn't* put in that `,@` now faces
breakage: they have to go and update all their code to cope with it. You
might say that they should have read the documentation, that upgrades need
careful testing, or that they are just bad programmers who should have
written perfect code in the first place. Either way, there's unhappiness
and perhaps a tendency to look again at other languages like Javascript
where this type of extensible callback API change is comparatively easier.

If the fallout is too bad, the change may be reverted, perhaps a new method
is added - `->each_with_index`. Huffman proponents declare that the library
is now unusable and proceed to fork it or rewrite from scratch, much
acrimony ensues, and in the middle of all that someone points out that we
clearly needed a *third* parameter, a reference to the underlying arrayref
so that you can look at items either side of the current one. This is seen
as a welcome distraction and immediately the userbase fragments into 3
different camps: the document said ,@ so get used to it,
`->each_with_index_and_arrayref`, and `->each(sub ($item, $index,
$arrayref) { ... }, WITH_INDEX | WITH_ARRAYREF)`. Perhaps someone else
proposes a `use Library ":v2"` to get the new behaviour, or puts in a
try-catch-until-we-stop-seeing-signature-failure workaround. The resulting
discussion becomes heated and is posted on various social media outlets,
with wise and informed commentary on all sides, but for some strange reason
the development on that original library is slowing down a bit, and perhaps
it's just a tiny bit less popular than it once was.

Anyway, you get the point. As a developer, I'm left thinking "if I can do
various boundary-breaking things like inspecting the caller's lexicals via
PadWalker, then _not_ being able to check what a coderef expects to be
called with seems like an odd omission".


> FWIW, I used to have *very* strongly *aligned* views with you about the
> warnings coming from sprintf Avar introduced ages back. At first I loathed
> that sprintf would warn if I passed in more arguments than it used. But
> over time I found that it actually saved me from embarrassment more often
> than it hindered my projects.  Not exactly your point, but not exactly a
> different one either.
>

Indeed so - and that's just a warning. This is a step further - it's a
runtime error. And again, in the sprintf case you controlled the format
string *and* the parameters, so it's understandable that you'd need to take
responsibility for making those consistent.


>
>> There are no tools or mechanisms offered to enforce this... so people
>> will leave it out, and things will work. They will work until a new version
>> of that library is released which now passes additional optional
>> parameters: then they will break.
>>
>
> Isn't this a question for the implementer of the callback mechanism?
>
>
>> Providing a way for the library code to deal with that - an explicit
>> opt-out for arity checking, *not* a change to the defaults across the rest
>> of Perl - seems like a basic courtesy to developers. If we are outright
>> rejecting that, I find that disappointing. More so if the given reason is
>> "we've been discussing signatures for 7 years already", rather than any
>> specific technical impediment.
>>
>
> But doesn't the @ mechanism do that?  Eg, if an author of an API that
> takes callbacks as a parameter should document that the callback API might
> change over time and thus all subs SHOULD have a @ in it?
>

The @ mechanism does not do that, though:

> There are no tools or mechanisms offered to *enforce* this... so *people
will leave it out, and things will work*. They will work until a new
version of that library is released which now passes additional optional
parameters: then they will break.

Making it easier to be backwards-compatible would benefit both the library
developers *and* the users.

Is there some introspective approach that would help here? Eg, if I was a
> callback author and I could interrogate that the signature did not have a @
> as its last clause then I could warn if someone supplied me a callback that
> didnt satisfy.
>

Yes. From the original email in that thread:

> If we had some sort of introspection we could do some kind of
> `bounded_invoke( $callback, @args )`  which would slice @args to no more
> than the signature says it wants.

Sadly the conversation drifted away from that original suggestion - I
didn't see any technical discussion on it.


> Anyway, I see the problem you are worried about and agree it has merit.
> But I'm not sure that the policy approach that rjbs is taking is
> unreasonable either. Is there a middle ground that would satisfy?
>

There is, yes - options have been proposed, including:

- introspection, as above
- provide a way to bypass arity checks for a specific call

If the answer is "no, we are not providing any of those", and that's an
official PSC decision, then there's not much more to be said. I have not
seen that stated explicitly (yet!). Would be nice to have a summary in the
archives explaining _why_ we aren't considering them - performance impact,
for example.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About