Discussion:
PEVANS Grant Report January 2024
(too old to reply)
Paul "LeoNerd" Evans
2024-02-09 18:06:51 UTC
Permalink
It will hopefully not come as much of a surprise that I now have a TPRF
grant too for core development work. Part of the requirements for that
is posting monthly reports on progress and time being spent. So here's
what I've been working on during January (plus the end of December that
got missed off the previous report)

My first time writing one of these so hopefully this is sufficient, but
here goes...


Hours:

9 = Updates to the `meta` module, a new CPAN release, adding a ->get
method, adding experimental warnings, ->get_or_add methods
https://metacpan.org/pod/meta
https://github.com/Perl/PPCs/blob/main/ppcs/ppc0022-metaprogramming.md

3 = Initial investigation into implementing PPC0019 "Quoted template
strings"
https://github.com/Perl/PPCs/blob/main/ppcs/ppc0019-qt-string.md

7 = Getting `use VERSION` to import a feature bundle
https://github.com/Perl/perl5/pull/21850

1.5 = Adding builtin::inf and builtin::nan
https://github.com/Perl/perl5/pull/21872

5 = Improvements to PADNAMEf_TOMBSTONE handling
https://github.com/Perl/perl5/pull/21887

3 = Lexical subroutine shadow warnings
https://github.com/Perl/perl5/pull/21915

Total: 28.5 hours.
--
Paul "LeoNerd" Evans

***@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Darren Duncan
2024-02-16 04:09:20 UTC
Permalink
My own thoughts on what are good design...

For actual mutable objects such as these are, the writer methods should return
void, as they are statements and not expressions.

Were we talking about immutable objects such that a "setter" is actually a
shorthand for creating a new object with the same fields as the invocant but for
one field value being changed, then it should return the new object. But this
doesn't apply here.

Personally I'm a strong advocate for immutable objects where one sets all the
fields at initial construction time, and not using chained mutators.

I'm not going to argue strongly against a chained mutator design, but that's my
preference to not encourage it.

Another thing to consider though is if you want to be conservative then making
mutators void in the initial version is safest because you're providing the
simplest functionality one can rely on. You can choose to later have them
return the invocant to support chaining mutators, but you can't change chaining
to void later without breaking things.

-- Darren Duncan
[...]
The only caveat is I realize the team never came to an agreement about what
the :writer would return. Some insist upon the invocant (chaining mutators)
while others want void. Returning a true value or previous value were minority
opinions.
Chaining is mostly only good for configuration and setup contexts.
You generally start out with a copy of a default configuration, as an object,
and then specialize it.
Once specialized enough, you call something like $task->run, to put the
configuration to use, to solidify it, to finish it.
For returning a previous value, explicitly use a get_set method, that itself
explicitly calls get and then set, as then both get and set can be overridden.
Any writer should return some (established or promised) final state in some way,
either inside the underlying (log-)object, or directly. Avoid global variables.
-- Ruud
my $sql= SQL -> from(t1 => "X") -> join(t2 => "Y", -on => {"t2.[% t1.name_lc
%]_id" => "t1.id"}) -> where(...) -> select(...) -> group_by(...) -> having(...)
-> order_by(...);
my $rv= $sql -> prepare(...);
if ($rv->err) {
    ...;
}
else {
    $rv= $sql -> execute;
}
Darren Duncan
2024-02-17 09:51:06 UTC
Permalink
On Fri, 16 Feb 2024 15:51:35 -0800
The "void" talk is a colloquialism rather than being literal, it
means in effect that :writer routines end with "return;", and are
explicitly not returning a value at all. Meaning that it doesn't
make sense to invoke them as an expression, just as a statement, so
no one should be writing "return $self->set_value($x), $x" in the
first place, so adding a return value would not break anything. Why
would one be writing that when it doesn't return a value? -- Darren
Duncan
attribute on subs, to warn of such things. Imagine
sub a {}
sub b :void {}
sub c {}
Pointless call of &main::b in non-void context at FILE line 5.
I just haven't got around to it yet.
Yes, that would indeed be nice to have, I would use it if it existed, and this
is then what :writer should use.

FWIW, from a general language design perspective, I prefer those languages that
make functions and procedures very structurally different routines in how they
are declared. So functions must return a value and be invoked within
expressions, and procedures must not return a value and must be invoked as
statements. Examples of languages like this include SQL and Pascal. In that
context, there is no "void" result type, instead you have a "procedure".

-- Darren Duncan
"Ruud H.G. van Tol" via perl5-porters
2024-02-17 23:37:39 UTC
Permalink
Post by Darren Duncan
FWIW, from a general language design perspective, I prefer those
languages that make functions and procedures very structurally
different routines in how they are declared.  So functions must return
a value and be invoked within expressions, and procedures must not
return a value and must be invoked as statements. Examples of
languages like this include SQL and Pascal.  In that context, there is
no "void" result type, instead you have a "procedure".
A procedure-call can still end in failure,
so it further depends on the definition of "return value".

Some functions use out-of-domain values to return error status.
I don't like that, IMO return value and state must be kept separate.

As Perl subs kan return lists, one could use
the first element for the return value
and the second element for the status:

  my ($rv, $err) = mysub(....);

But then mysub() needs to use wantarray()
(which actually means wantlist())
to find out what it should return.

Procedures generally have side effects.
Procedures can be allowed to change the contents of ("output") parameters,
which is much like a return value.

Functions are cleanest if they don't have side effects.
But for example memoization already blurs that.

-- Ruud
Darren Duncan
2024-02-17 23:53:37 UTC
Permalink
Post by "Ruud H.G. van Tol" via perl5-porters
Post by Darren Duncan
FWIW, from a general language design perspective, I prefer those languages
that make functions and procedures very structurally different routines in how
they are declared.  So functions must return a value and be invoked within
expressions, and procedures must not return a value and must be invoked as
statements. Examples of languages like this include SQL and Pascal.  In that
context, there is no "void" result type, instead you have a "procedure".
A procedure-call can still end in failure,
so it further depends on the definition of "return value".
Some functions use out-of-domain values to return error status.
I don't like that, IMO return value and state must be kept separate.
As Perl subs kan return lists, one could use
the first element for the return value
  my ($rv, $err) = mysub(....);
But then mysub() needs to use wantarray()
(which actually means wantlist())
to find out what it should return.
Procedures generally have side effects.
Procedures can be allowed to change the contents of ("output") parameters,
which is much like a return value.
Functions are cleanest if they don't have side effects.
But for example memoization already blurs that.
Yes. I kept things simpler in my statement above. But a more expanded version
is: From a general language design perspective, functions should be pure and
not have side effects, and return values are determined just by arguments.
While anything with side effects would be a procedure, and if that procedure has
outputs to the caller it can be through reference/inout parameters. As for
indicating errors, depending on what one prefers, this could be an output
parameter or a thrown exception. Typically one would expect errors/exceptions
to come from procedures and not functions, unless indicating inappropriate
arguments or divide by zero or out of memory or such. I also don't like the
idea of wantarray/etc and feel if one wants different behavior for different
calling contexts like that they should be separate routines with different
names. Anyway this thread is more of a tangent and I likely won't take the time
to discuss it further. -- Darren Duncan

Loading...