On Thu, Jan 02, 2020 at 07:49:28PM +0100, Marc Chantreux wrote: > On Thu, Jan 02, 2020 at 10:42:54AM -0600, danieljb...@icloud.com wrote: > > I don't understand why people say that perl's flexibility is a negative. > > because sometimes, flexibility permit some endless sterile debates about > the coding style.
Well, OpenBSD has got style(9). I have some specific adaptations for perl, because a lot of the rules are for C. Here are my current guidelines for OpenBSD perl tools. In general, things are written following style(9) adapted for perl. Specifically, - named sub *are* functions. So sub f { my ($arg1, $arg2) = @_; ... code } - three styles of parameter grab for methods: sub m1 { my $self = shift; } No other parameter. sub m2 { my ($self, $p1, $p2) = @_; } when getting all parameters (no check on the number usually) sub m3 { my $self = shift; ... do_something_with(@_); } for functions with unlimited parameters after the first one (dubious whether this changes anything for performance reasons) - wantarray should *only* be used for optimization purposes (yes/no answer instead of full list). Doing otherwise utterly complicates matters. - I almost never put extra parentheses, and use the "4 space indent" rule for continuing statements. - chained index lookups should ditch the extra -> . prefer $self->{a}{b} to $self->{a}->{b} - don't put quotes around indices unless absolutely necessary (keywords) and don't use keywords for keys. - anonymous subs are part of the code: So: my $s = sub { my $self = shift; ... }; Note a full indent because the inside looks like code. - modern perl prefered, so $value //= something; prefered over $value = something if !defined $value; - autovivification welcome. push @{$self->{list}}, value; is perfectly fine without defining $self->{list} first. Note that if (@{$self->{list} > 0) *won't* autovivify list, so it can be used for "does the list exist and is not empty" instead of if (exists $self->{list} - I should probably normalize towards banning implicit return ? - should I prefer "always refs" over explicit % / @ ? There is a slight legibility problem: my @l; is more readable than my $l; (this is a list) and my $l = []; takes slightly more memory. - most things unless explicitly being debugged should set $DB::inhibit_exit = 1 right afer a fork and before an exec. And I have some further general rules, learnt from past mistakes. The perl package tools follow some stylistic and practical guidelines - all new development should be object-oriented. Have a package under either OpenBSD or DPB, and pass operations to a constructed object (generally name the constructor new unless you have better options) if you need to keep state, or to the class name proper. Examples: my $pkgpath = DPB::PkgPath->new('devel/quirks'): say "Normalized version is ", $pkgpath->fullpkgpath; $state->errsay(OpenBSD::Temp->last_error); older code sometimes does not respect that. It hasn't been converted because it's currently not worth it. But there have been many instances where I've actually regretted not doing things that way sooner. The object itself is usually called "$self" unless there are reasons not to. Since there are no access control restrictions in perl, most often internal methods are just prefixed with _. Stylistically, methods without parameters don't need parameters, so I don't write them, prefer $object->foo to $object->foo() It makes it less cumbersome to chain methods, e.g., $object->foo->bar(whatever); - in the interest of chaining methods, stuff that tweaks an object should return the object itself, so that $self->set_foo(1)->set_bar(2)->run will actually work - a lot of code creates "unique" objects. The pattern is to have a %cache hash in the package, and have the normal constructor do things under the radar, calling create as needed. create won't normally be used by client code. - a lot of code creates "just in time objects". Error.pm containt the OpenBSD::Auto class, that can be used to create jit values, it contains one single construct, cache, that is used like so: OpenBSD::Auto::cache(solver, sub { require OpenBSD::Dependencies; return OpenBSD::Dependencies->new(shift); }); so that the first call to $self->solver(x) will instantiate $self->{solver} to the required object. And that call and all subsequent calls will return the same object. - there are way less files than classes. Things are organized in a "put a whole set of related things together in the same file". Full OO also means you don't need to use Foo; from the start, you can require Foo; dynamically, thus loading it later. This does speed up the startup of tools significantly. - in general, singletons are frowned upon. We still have a few (list ?), mainly as cached values in specific packages. There is some kind of global state though, and that's generally handled through the $state object. - DON'T USE MULTIPLE INHERITANCE unless absolutely necessary. It's almost always a mess. Grabbing some behavior from a class (mixin) is best done on a per-method basis. Know about &function; (without the paren) which is a "goto that sub with my @_ totally unchanged". So mix-ins can (and usually) do: package B; sub f { &A::f; # delegate to A }