Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Re^2: Recap: The Future of Perl 5

by Ovid (Cardinal)
on Aug 23, 2018 at 23:41 UTC ( [id://1220970] : note . print w/replies, xml ) Need Help??

in reply to Re: Recap: The Future of Perl 5
in thread Recap: The Future of Perl 5

Regarding this code:

sub fib { my $nth = shift; (caller)[3] eq 'fib' or $nth !~ m{^\d+$} or @_ and die $fib_die_msg; return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ); }

That's a perfect example of the sort of things that an expert Perl programmer can understand, but it's not welcoming to newcomers. It also has two serious bugs I see off the top of my head (and that's before parsing precedence, which I can't with that example).

Optional typing in signatures would improve that, for sure - but there's Params::Validate for instance. Then, what should happen if a sub takes an Uint and gets a polymorphic object which resolves to a Uint in numeric context via overloading, but as a filehandle at I/O ? Would we need typecasting? Would the object be aliased to its numeric interpretation in such a subroutine body, or would other slots and/or behaviors still be available and valid?

Again, while Params::Validate is an excellent module, it is not in core and, if it was, it still means it's not core Perl and it's the sort of thing we'd have to remember to use (and to be honest, the confusing interface is an artifact of the fact that it's not core perl).

I'm specifically arguing that core features developers expect in many mature languages should be core to the Perl language itself, and not provided by external modules.

And your comments about "resolves to a UInt" are the sort of issues that many other languages need to resolve. That problem isn't unique to Perl, so Perl should find a way to solve it in a way that fits "the principle of least surprise." I completely agree that we have to make some hard choices (should the string "3" map to the integer 3?), but we shouldn't let these sorts of questions stop us from solving this problem.

Replies are listed 'Best First'.
Re^3: Recap: The Future of Perl 5
by shmem (Chancellor) on Aug 24, 2018 at 15:02 UTC
    That's a perfect example of the sort of things that an expert Perl programmer can understand, but it's not welcoming to newcomers. It also has two serious bugs I see off the top of my head (and that's before parsing precedence, which I can't with that example).

    I agree, my bad.

    Care to elaborate about the bugs? I see that fib "5\n" would be allowed, so the matching should use \z; then, restrict to ascii via the /a modifier. Precedence is ambiguous (and it shows not to work as intended), so parens are necessary and that should be:

    (caller)[3] eq 'fib' or ($nth !~ m{^\d+\z}a or @_) and die $fib_die_ +msg;

    Something else?

    Of course, this is an acme example only given for showing "it can be done", but such constructs have poor maintainability - which is the entry point of your talk, I guess.

    I totally agree with you that good function signatures and an optional, gradual typing system would be great to have, for some style of programming. But looking the other way round, that would weaken a great strength of perl:

    Perl is amazingly good at being lousy at typing.</sarcasm>

    For the sake of orthogonality, variable type constraints of course would need to be available for every kind of declaration. Currently, the function signature stuff misses that, but it can be done - not with core perl as you say, but with packages belonging to the core, e.g.

    use strict; use warnings; use 5.20.0; use Attribute::Handlers; package Uint { require Tie::Scalar; @Uint::ISA = qw(Tie::StdScalar); sub STORE { my ($p,$f,$l) = caller; $_[1] !~ /^\d+\z/a and die "not a positive integer in package $p file $f line + $l, aborted"; ${$_[0]} = $_[1]; }; } sub UNIVERSAL::Uint : ATTR(SCALAR) { tie ${$_[2]}, 'Uint' } sub fib { my $nth : Uint = shift; # check for extra items in @_ missing return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ); } say fib @ARGV;

    at the cost of lousy performance. On my machine, a fib(30) is

    • 0m0.923s plain (with no checks)
    • 0m3.688s with my version (with fixes from above)
    • 4m4.759s with Attribute::Handlers and Tie::Scalar

    I'm far away and below of the current affairs and state of perl development/improvement, but implementing attribute handling in the core, type constraints via short-circuiting tie for common types (facilitating user-defined types) and allowing attributes for function signature variable attributes in the parser e.g.

    sub fib :prototype($) ($nth : Uint) { # check for 1 == @_ already done ... }

    probably implementing all that in XS first, would be a huge gain.

    There are some things I would wish to have in core proper apart from that and inlining via keywords (and modifiers where sensible):

    • iterators as first class citizens
    • inside-out hashes and arrays (think Hash::Util::FieldHash as default implementation, connecting slots would require a keyword)
    • more contexts than void, scalar, list
    • return constraints inside a subroutine (think Uint sub fib ($nth : Uint) where returning anything but an Uint is an error)
    • user defined parser extensions (rewrite from bison/yacc to perl)
    • ...

    but then, I should start to explore what is called perl 6, I guess, and many of these things surely have been discussed long ago.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      Type::Tie does similar to your example tie code. And there's XS implementations for a lot of types in Type::Tiny::XS. I really should look at the possibility of implementing the tie stuff in XS too.

      use Type::Tie; use Types::Common::Numeric qw(PositiveOrZeroInt); tie my $x, PositiveOrZeroInt;

      Combining it with Attribute::Handlers could be a fun idea.

      Also, you probably want to use [0-9] in your regular expression, not \d. Yes, there's a difference.