Firstly… Class::Tiny::Antlers Whaaaaat?!?! One of my modules is referenced by the core Perl documentation? How did that happen?! Secondly, the Moose example could be simplified quite a bit. I feel you're making it deliberately verbose by not using sub signatures for example. package Cache::LRU { use Hash::Ordered; use Moose; use MooseX::Types::Common::Numeric qw/PositiveOrZeroInt/; use namespace::autoclean; has '_cache' => ( is => 'ro', isa => 'Hash::Ordered', default => sub { Hash::Ordered->new }, ); has 'max_size' => ( is => 'ro', isa => PositiveOrZeroInt, default => 20, ); sub set ($self, $key, $value) { if ( $self->_cache->exists($value) ) { $self->_cache->delete($value); } elsif ( $self->_cache->keys > $self->max_size ) { $self->_cache->shift; } $self->_cache->set( $key, $value ); } sub get ($self, $key) { return unless $self->_cache->exists($key); return $self->_cache->set( $key, $self->_cache->delete($key) ) + ; } __PACKAGE__->meta->make_immutable; } [download] Still more verbose than your proposed syntax, but not as bad as it was. Also, if you used Moo, you could avoid the make_immutable stuff because the constructor automatically immutablizes the class the first time it gets called. To be honest, Moose seems verbose because this is such a simple class. It means that boilerplate imports and stuff starts taking up a significant portion of the class. In a longer class with more methods, the difference would be a lot less pronounced. I'mma give a Mew example because Mew is kinda cool. package Cache::LRU { use Hash::Ordered; use Mew; has _cache => InstanceOf['Hash::Ordered'], (default => sub { Has + h::Ordered->new }); has max_size => PositiveOrZeroInt, (default => 20); sub set ($self, $key, $value) { if ( $self->_cache->exists($value) ) { $self->_cache->delete($value); } elsif ( $self->_cache->keys > $self->max_size ) { $self->_cache->shift; } $self->_cache->set( $key, $value ); } sub get ($self, $key) { return unless $self->_cache->exists($key); return $self->_cache->set( $key, $self->_cache->delete($key) ) + ; } } [download] toby döt ink

++ from me and I agree with all of your points (except I didn't make it deliberately verbose because it was thrown together quickly; my bad). However, Mew, like Moose, or Moo, is not core. Not having a clean, minimal syntax for core OO is part of the problem I would love to see us address (and obviously, I mean more than bless and @ISA ). Cheers,

Ovid Hire me for training or software development.

Note that Perl does ship with a (still) core module called Class::Struct, which offers a simple syntax for OO programming. An example I wrote 2 years ago is somewhat similar to the Point class example you provided. I only wrote it as a rebuttal to a claim that Perl OO programming is very hard without installing something from CPAN package Planet; use Class::Struct mass => '$', radius => '$'; use Math::Trig; sub density { my $self = shift; my $vol = 4/3*pi*($self->radius)**3); return $vol/($self->mass); } package main; use Planet; my $Jupiter = Planet->new(mass => 1.8E27, radius => 6.9E7); print "Jupiter has mass of " . $Jupiter->mass . " and "; print "radius of " . $Jupiter->radius . "

"; print "It's density is " . $Jupiter->density . "

"; [download] Not as clean as your proposed syntax, but is something that can be used without needing anything from CPAN. And there are limitations, such as Class::Struct classes can only inherit from UNIVERSAL. Edit: corrected syntax as pointed out by LanX. Also, changed mod:// links to doc://

Agreed, but it's not core Perl, it's not well-known, and it's not nearly as useful as the proposed syntax. Cheers,

Ovid Hire me for training or software development.

Agreed, but it's not core Perl I think it would aid clarity to your arguments immensely if you could choose a different word for what you want. The Perl community has been using "core" to mean precisely modules which are bundled with the perl distro since last millennium (and I know you know this too). It's confusing if you start to use it to mean something else.

I agree, your proposed syntax is much nicer. I did see somethings surprising. In: class Point { has Num ($x, $y); method inverted () { return Point->new( x => $y, y => $x ); } } [download] you have $x instead of $self->x (likewise for $y ). I found this surprising, and had to pause to think for a second or 2. How common is it in other OO languages to not need "self" to reference instance variables in instance methods? Personally, I don't recall ever seeing it done without "self". (Been so long since I last used C++ that I had forgotten.) More surprising was: class Cache::LRU { use Hash::Ordered; our $num_caches = 0; # class data (unused + in this example) my $x = Hash::Ordered->new; # private instance da + ta has UInt $max_size = 20; # public instance dat + a method set ( Str $key, $value ) { if ( $x->exists($key) ) { $x->delete($key); [download] where $x is also an instance variable. (Just some additional thoughts.)

Hi RonW, I did not know about this Class::Struct module, this seems to be quite interesting. I'll have a look at it. Thank you for having pointed to it.

> use Class::Struct mass => $, radius => $; How is this legal Perl syntax? A short glimpse into Class::Struct seems to indicate that you rather meant use Class::Struct mass => '$', radius => '$'; Right? Cheers Rolf

(addicted to the Perl Programming Language :)

Wikisyntax for the Monastery Football Perl is like chess, only without the dice

You're right. It was in a reply I wrote quickly and didn't get to test before I posted. (Also, thanks for the doc:// linking tip.)

I am an XP whore and if I reply multiple times, I'll get more XP. So have more thoughts. Point Class Your Perl version of the Point class can be simplified a lot using the features of existing modern versions of Perl. use v5.20; use experimental 'signatures'; package Point { sub new ($class, $x, $y) { bless [$x, $y] => $class; } sub x ($self) { $self->[0] } sub y ($self) { $self->[1] } sub inverted ($self) { ref($self)->new($self->y, $self->x); } } [download] Yeah, I cheated by making x and y read only, but dammit they should be read only. If they change, it's a different point, so you should make a different object. Incidentally, making them read only makes the implementation simpler in Perl, but harder in the other languages you gave examples for. Type Checking in Core As for type checking in core, there's already parser support for: my Foo $foo = Foo->new(...); [download] However, other than checking that a package "Foo" exists, core Perl doesn't do anything with that. I think the best route for adding decent type support to Perl would be: Provide an API which allows a type library module to define types such as my Str $x where Str isn't a package name and $x would be a plain old string not a blessed reference. These should be scoped (either lexically or by package). If you try to use a type which hasn't been declared for lexical scope, Perl assumes you meant it as a class name. I'll provide an outline of a simple and perhaps workable API below. Bundle a module with core which defines a bunch of predefined types. Perhaps automatically load it if a recent enough use VERSION line is given. Including the following in the core set of types shouldn't be controversial because they conform roughly to the existing types Perl kinda exposes to end users already. All the standard ref types: "ArrayRef", "HashRef", "ScalarRef", "CodeRef", "GlobRef", "RegexpRef", etc.

The types of value that can be stored in an SV: "Int", "UInt", "Num", "Str".

"Defined" and "Blessed". Having a type called "Undef" would probably be non-controversial, but it's also pretty useless to declare a variable which will be undef and which will always be undef. There are loads of other types which are often handy, like "PositiveNum" but which seem likely to end up in bikeshedding. (For example, should "PositiveNum" include zero because that's more useful in most cases, even if zero isn't strictly positive. Should it be called "UNum" for consistency with "UInt", even though the former isn't a well-established name like the latter is, and "Unum" is Latin for "one" in the accusative form. Should it accept overloaded objects? Et cetera.) To avoid such bikeshedding, plus to allow people to define their own useful application-specific type constraints, I think the core set of types should be kept small and non-controversial, with the API mentioned above being used to define other types. Allow these types to also be used in sub signatures. sub foo (Int $bar, Str $baz) { ...; } [download] Would be roughly equivalent to: sub foo { my Int $bar = $_[0]; my Str $baz = $_[1]; die "..." if @_ > 2; ...; } [download] Sketch of an API for Pluggable Types If Perl encounters: my Foo $x = $y; [download] It should interpret "Foo" much the same way it would in the case of Foo->new() . That is, if there's a Foo sub, Perl should treat it as Foo() . If there's no "Foo" sub, then "Foo" is treated as a package name (string). Perl would make this decision based on whether the Foo sub existed at compile time. After that, any time a value is assigned to $x , then one of the following happens: "Foo"->CHECK_SCALAR(\$newvalue); Foo()->CHECK_SCALAR(\$newvalue); [download] I'm naming the method CHECK_SCALAR instead of just CHECK to allow for it to possibly be extended to arrays and hashes. Passing the value by reference for added efficiency, and because checking arrays and hashes will likely require passing a reference anyway. This would be the basic API for creating user-defined types. There should probably also be an XS API which would allow a value to be checked via a single xsub call rather than all that method dispatch stuff. The basic type library bundled with core would make use of the XS API, because I'm pretty sure we don't want using the most basic type checks in signatures to slow down our code very much. Oh yeah, and also: sub UNIVERSAL::CHECK_SCALAR (Str $class, ScalarRef $sref) { require Scalar::Util; unless (Scalar::Util::blessed($$sref) && ${$sref}->isa($class)) { require Carp; Carp::croak("..."); } } [download] toby döt ink

However, other than checking that a package "Foo" exists, core Perl doesn't do anything with that. It's used for compile-time and run-time checking of the keys to hash refs. It's the mechanism that fields.pm uses. Dave.

Hmm, interesting. Do you know how much of that is in the core Perl (as Ovid is using the term "core"… perl.exe itself, no modules), and how much is done by fields.pm and friends? If it's mostly done by the modules, then I don't see a problem with there being multiple ways of hooking into my Foo $x . TIMTOWTDI after all. toby döt ink

Provide an API which allows a type library module to define types such as my Str $x where Str isn't a package name ... Again, that fails horribly, IMHO. For the shops which adopt that, every time I go into a shop, I have to discover how their implementation of "Str" is different from the implementation of "Str" at my last shop, which in turn is different from the implementation of "Str" I would expect in other languages. Core types that people expect should be in the core (and not in libraries I have to remember to load!). Further, their behavior should be as boring and predictable as possible. As for an extensible API? Sure, I can get behind that if the arguments which would invariably ensue are brief. Otherwise, the bike-shedding would stand a good chance of guaranteeing that nothing would get done. Bundle a module with core which defines a bunch of predefined types. Perhaps automatically load it if a recent enough use VERSION line is given. Again, if you have to remember to do a particular thing to get benefits, it hurts the Perl community. For example, use strict; use warnings; should have been the default a long time ago, with additional action taken to disable them. It's less common now, but we still have to fight to remind developers to enable strict . That's years of arguing over a basic issue that could have been spent more profitably writing code and developing the language. Cheers,

Ovid Hire me for training or software development.

Even with something as simple as Str, if you put ten Perl developers in a room, I'd expect them to have eleven different opinions on how it should be implemented. my Str $x = $y; [download] If $y is undef, then $x should be "" because of type casting.

is undef, then should be "" because of type casting. If $y is undef, then there should be an exception thrown because undef isn't a string.

is undef, then there should be an exception thrown because undef isn't a string. If $y is an overloaded object, then $x should now be an overloaded object.

is an overloaded object, then should now be an overloaded object. If $y is an overloaded object, then $x should now be the stringified version of that object.

is an overloaded object, then should now be the stringified version of that object. If $y is an overloaded object, then there should be an exception thrown because an object isn't really a string and overloading sucks anyway.

is an overloaded object, then there should be an exception thrown because an object isn't really a string and overloading sucks anyway. Even if $y is a non-overloaded object, $x should now be the stringified version of that object.

is a non-overloaded object, should now be the stringified version of that object. If $y is 42 (no quote marks), then there should be an exception thrown because integers aren't a subset of strings dammit!

is 42 (no quote marks), then there should be an exception thrown because integers aren't a subset of strings dammit! If $y is 42 (no quote marks), then $x should be "42" (with quotes) and poking around with B:: stuff you should be able to tell the difference between them.

is 42 (no quote marks), then should be "42" (with quotes) and poking around with B:: stuff you should be able to tell the difference between them. A lot of these cases could be handled by using warnings instead of exceptions. It's basically the same kind of error as use warnings "numeric" anyway, and we're happy enough having those be non-fatal.

anyway, and we're happy enough having those be non-fatal. Empty strings are always an error in my application, so if $y is "", it should throw an exception, shut down the computer, and set the building on fire. (In all seriousness, I know of at least one case in Perl where empty strings are special-cased, treating them differently from non-empty strings.)

is "", it should throw an exception, shut down the computer, and set the building on fire. (In all seriousness, I know of at least one case in Perl where empty strings are special-cased, treating them differently from non-empty strings.) But dualvars! Waaaaaah! toby döt ink

Some notes below your chosen depth have not been shown here

Ovid: Again, if you have to remember to do a particular thing to get benefits, it hurts the Perl community. For example, use strict; use warnings; should have been the default a long time ago, with additional action taken to disable them. So, Joe SysAdmin does an upgrade one day, and finds half of the old perl scripts on the system are broken. This is not something you want to have happen, not when we're still fighting the fallout from the "perl is dead" smear campaign. I could see an argument that stuff like "use 5.10.0" should've implied strict and warnings also... or for that matter that cromatic's Modern::Perl should ship with the core library, it's a lot easier to type correctly (I had to double-check that you really need "5.10.0"). Backwards compatibility is really and truly important, and it remains important-- it's one of the things that perl has always gotten right (and the new kids keep screwing up).

Some notes below your chosen depth have not been shown here

I'm looking only at your first examples in that post for now. To write a robust Fibonacci function, you might write something like this: sub fib { croak("…") if @_ != 1; my $nth = $_[0]; croak("…") if not defined $nth; croak("…") if $nth !~ /^+?\d+$/a; return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ); } [download] You are being unnecessarily verbose, aren't you? All those checks just fold into two: my $fib_die_msg = 'fib() takes one positive integer as argument, abort + ed'; sub fib { my($nth = shift) =~ m{^\d+$} or die $fib_die_msg; @_ and die $fib_die_msg; return $nth if $nth <= 1; return fib( $nth - 1 ) + fib( $nth - 2 ); } [download] The two checks can also be written on one line and no harm done: sub fib { my($nth = shift) =~ m{^\d+$} and ! @_ or die $fib_die_msg; ... } [download] The checks can be skipped completely, if the caller is the recursive subroutine itself: 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 ); } [download] 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? I personally believe that such constraints go against the Camel's hair, and against the best thing perl has since sliced bread, which is context awareness, which forces the programmer to be aware of the context in which they are moving things around. Also, neither your Ruby, PHP nor Python versions do any parameter checks, but you write them for your perl5 version. Write an equivalent Python class, and you will have exexption definitions and try/catch branches and such. No need to be unfair to perl to make a point - and no need to blow away the very foundations of perl either ;-) perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

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 ); } [download] 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. Cheers,

Ovid Hire me for training or software development.

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

" 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; [download] 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; [download] 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 ... } [download] 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)

where returning anything but an 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'

++ovid, you obviously make your points much better than I possibly could from sheer memory of what you said. I'm still quite happy that I launched the discussion about the ideas you developed in that keynote in Glasgow.

Re the OO part - there are a few problems with the class idea. Firstly, how do class and package relate? Are they synonymous? Can you have one inside the other? On a somewhat higher level, what if the class construct isn't the best way to do OOP. Some newer languages (Go and Rust) have avoided having a class construct (but still support some flavour of OOP). And going back much further, we find works like the GOF book, which was based around two principles Program to an 'interface', not an 'implementation'



Favor 'object composition' over 'class inheritance' So instead of just copying a sub-optimal construct that some other languages copied from others, maybe we ought to step back and look for better abstractions? My own lengthy contemplation has led to a prototype of what such abstractions could look like. Mic provides Interfaces (which support Eiffel-like contracts) as a primary abstraction, and Implementations as a secondary abstraction. I worry that what gets implemented would be "weaker" than what can already be achieved using libraries.

For fairness you should show Moo for the point example, package Point { use Moose; has [qw/x y/] => ( isa => 'Int', is => 'rw' ); sub inverted { my $self = shift; __PACKAGE__->new( x => $self->y, y => $self->x ); } } [download] Shy of that, this argument seems to mostly boil down into not core. This seems to be very much a reiteration of Stevan's thinking and work with Moxie. Good luck on it, it's just not very interesting to me. Out of all the problems I've had with Perl the inclusion of Moose in CORE, or a lightweight object system doesn't make the top-10. In my estimation the best thing Perl has going for it is Moose.



Evan Carroll

The most respected person in the whole perl community.

www.evancarroll.com Evan CarrollThe most respected person in the whole perl community.

We can easily speculate about a new "sexy" syntax which "Easy things should be easy, and hard things should be possible"°. The crucial problem for the acceptance is backwards compatibility , both semantically and syntactically. Most of us are stuck with an older version of Perl before the team decides to upgrade, so it would be very important for acceptance if the "sexy" syntax could already be run there. NB: It doesn't need to be fast ... just complete. referring to a new version for speed could be a good incentive and marketing. let me suggest something, would this syntax be acceptable? { use class Point => ISA-LIST; my ($x, $y); my $z :ro; our @points; # class var sub inverted :public { return Point->new( x => $$y, y => $$x ); } } #end of scope [download] please note that use class Point could be shortend to class Point with Keyword::Simple for Perl > 5.13 The whole mechanism would work with a safe source filter² which just injects some boilerplate OO package header at the _beginning_, and a callback which is triggered at the end of scope.* The callback would inspect the STASH of the package and use PadWalker to identify instance variables. The indentified subs (like "inverted") would be patched and wrapped with initialising code mapping the first argument to $self ( a closure var from the boilerplate). Wrapper would look like something like my $old_meth = \&Point::inverted; *Point::inverted = sub { $self = shift @_; $x = \ $self->{x}; $y = \ $self->{y}; goto &$old_meth; } [download] ( I deliberate used references for instance vars, to have a visual clue) This and the use of attributes for more "exotic" features would allow us to stay comaptible to the old perl model, since $self still works

and shorten the syntax like our competitors.

we could stay compatible to older OO code from the most popular OO frameworks (M** whatever) by using this syntax as proxy frontend

people comming from other languages like Python would feel instantly at home

we can not only auto-generate ->new but also go by the Python convention to have a constructor sub called Point() (DISCLAIMER: I didn't check yet the timing of attributes and triggering of the scope callback yet) Of course the "real" implementation would use dedicated opcodes and ammend the parser, hence be mmore performand. Comments? Cheers Rolf

(addicted to the Perl Programming Language :)

Wikisyntax for the Monastery Football Perl is like chess, only without the dice °) didn't that use to be Perl's motto? (update: yep) *) NB you don't need the block if there is only one class per file. ²) safe because the source filter is just injecting code at the beginning and doesn't attempt to parse Perl.

> but also go by the Python convention to have a constructor sub called Point() to elaborate further this: class Point: def __init__(self, x, y): self.x = x self.y = y def inverted(self): return Point(self.y,self.x) [download] could be translated to class Point; sub INIT($X,$Y) { $$x = $X; $$y = $Y; # or $self->{y} = $Y; } sub inverted { return Point($$y,$$x) # or Point->new($$y,$$x) # or Point->new($self->{y},$self->{x}) # or Point($self->{y},$self->{x}) # ... TIMTOWTDI } [download] People comming from Python would instantly feel at home and little by little discover more elaborated possibilities by using :attributes. Cheers Rolf

(addicted to the Perl Programming Language :)

Wikisyntax for the Monastery Football Perl is like chess, only without the dice

..twitter... How could you leave Badger off the list?