develooper Front page | perl.perl5.porters | Postings from June 2021

Re: RFC: define meta operator

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
June 14, 2021 10:39
Subject:
Re: RFC: define meta operator
Message ID:
20210614103850.GR16703@etla.org
On Sat, Jun 12, 2021 at 10:12:39PM +0200, Branislav ZahradnĂ­k wrote:

> Note:
> This is part of larger set of RFCs (Context Oriented Programming)
> which can be reused by other (unrelated) RFCs.

Parts of this are difficult to make sense of without those other RFCs.
What is extracted here feels more like the Meta-Object-Protocol syntax,
rather than the interface average users would use most of the time.

> Note 2:
> Few times I'll mention [Ovid's Cor proposal](https://github.com/Ovid/Cor/)
> where this RFC may overlap (conflict) with it using different expressivity
> (showing support to his effort).

This RFC is part of something much larger in scope than COR. Also, COR is
further along - there are working prototypes to explore the design. Are
there prototypes for any parts of this proposal? It's hard to think about it
from just design documents.

Also, this proposal is (re)using core attributes such as :public and :shared.

COR isn't firm yet. PSC are confident that (something like) COR will land in
the core at some point, and hence *its* *eventual* choice of terms, and
definitions for them, will have to be the core's canonical definitions of
these, to avoid inconsistency and ambiguity. So to me it seems maybe
premature to build massively on a foundation that is might move.

> Current perl ecosystem has many approaches how to specify meta properties
> in different entities
> 
> - package
>   - perl core - set package variables (`@ISA`, `@EXPORT`, ...)
>   - Moo/Moose - functions like `extends`, `with`
>   - Ovid's Cor proposal - keywords `isa`, `does`
> 
> - function / method
>   - perl core - prototypes
>   - perl core - signatures
>   - perl core - attributes

>   - perl core - `bless`, `tie`
>   - perl core - intention often implemented by using `//`, `//=`, ...
>   - Moo/Moose - function `has`
>   - `Moose::Util::apply_all_roles`
>   - Ovid's Cor - keyword `has`
> 
> Definition of binary define-meta operator will provide unified way to express
> intention (which leads to non negligible improvement to code readability)

You're proposing a syntax to unify

* isa
* does
* function signatures
* function attributes
* bless
* tie
* exports

and others. These are many disparate things.

You're proposing a single syntax to make different things look similar.

This removes clues about what is going on. This doesn't make code easier
to read.

I can't agree with your key motivation of "non negligible improvement to
code readability".

I feel strongly that this plan will make everything harder to read. It's as
if you're suggesting that everyone should program in Moose's Meta Object
Protocol *directly*, instead of using all the syntax it adds to make
easy things easy.

> `when (condition) => value` expression can be used for conditional assignment
> Condition is stored and evaluated when given meta property is evaluated.
> 
> basic variant can contain any number of when expressions
> ```
> 	LHS := :property
> 		when (cond-1) => value
> 		when (cond-2) => value
> 		=> otherwise
> ```

PSC are confident that given/when will be reworked, possibly substantively.
We can't be sure of the exact semantics of future behaviour, of even if we
will stick to the current names. Building a proposal that (implicitly)
relies on the status quo is not a good idea yet.

> C-API v0 should provide:
> - `is_meta_property_set (object, meta_property)`
> - `list_meta_properties (object`
> - `meta_property_value (object, meta_property, context)`

Fundamental to this proposal seems to be that this C API exists.

Is there any plan for *how* these properties should be stored internally?
Having that is the foundation for the implementation, but there doesn't seem
to be any idea for this other than these C prototype declarations.

Related to this - not everything in Perl is "first class". You can take
references to functions and closures. You can take references to regexs.
You can't take references to blocks, or to stack frames, but in some of the
other messages you've sent, you are using syntax that wants to set
properties on things like these, which can't (currently) be done in any
way unified with CODE, ARRAY, HASH, SCALAR or Regexp.

> 	sub foo
> 		:= :lvalue
> 		:= :is => CORE::Array::
> 		:= :public # (Cor attribute)
> 		:= :shared # (Cor attribute)
> ```
> 
> Runtime
> ```
> 	sub foo {
> 		__SUB__ := :is => CORE::Hash::;
> 	}

These aren't defined by the Perl core. It's not meaningful to specify meta
operators that act on something that isn't yet itself defined.


> 	has $var
> 		:= :is => CORE::Number::
> 		:= :is => CORE::Defined::

This is implying a type system exists in Perl 5, and that "Number" makes
sense in it. Again, that's not a given - Perl 5 simultaneously has
storage representation (eg IV, PVIV, PVNV, PVMG, PVLV) and flags that are
set to indicate which type (or types, *plural*) that value is.

There's not one obvious way to map those two internal hierarchies into a
sane Perl-space type system.


> ### :required

> 
> ```
> 	package Foo {
> 		has foo := :required;
> 		has bar := not :required when ($foo % 2);

I know from chatting with Jonathan that efficiently implementing any sort of
complex constraint like this is a real stinker, and something you have to
design in from the start (as part of your multi-dispatch). We don't have
multi-dispatch - anything like this is likely to be extremely inefficient.

> 	sub authenticate {
> 		has login := :required;
> 		has password := :required;
> 	}
> ```
> 
> When set on variable it throws an exception unless there already was
> value assigned to it.


meaning

    die "Constraint failure"
       if !defined $option_password && unexpressable_thing $option_login;


This line alone would warrant an RFC - this is proposing a whole new syntax
paradigm for thinking about optional values and the constraints between them.

To me, this feels about as Perl-ish as Raku. As in, clearly Perl-ish.
But not Perl.

> ### :readonly

> When specified on variable, makes variable readonly (or write once if
> has no value yet)

Write once - that's not the same defintion of readonly that any other
language I know uses. "Must have an initialiser" is the common way.

> When specified on sub, signals that sub only reads arguments

I feel that this is conflating different concepts into one word.
"Only reads arguments" means what - that it's not allowed to modify its
arguments in place?

*Most* of subroutine signatures are about clearer more efficient syntax for
copying arguments and setting defaults - the use of "modify in place"
arguments is really rare.

On the other hand, if I misunderstood this, and you mean that the subroutine
doesn't modify any part of complex data structures passed into it -
enforcing this sort of deep readonly with the current implementation is
pretty much a non-starter.

> and more derived from
> https://github.com/happy-barney/perl-poc/tree/perl-features/COP


My summary is that it feels like this syntax is part of much larger design,
for a language *derived* from Perl. To take the "family" analogy often used,
this plan is a picture of another "sibling" of Perl, not a picture of Perl
later in life.

(Except where I explicitly mentioned the PSC, the above is my opnion, not
the PSC's. I don't what the other 2 (soon 3) members of the PSC think, and
they may well disagree with me.)

Nicholas Clark

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