Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-30 Thread Dan Ackroyd
On Thu, 29 Apr 2021 at 09:14, Guilliam Xavier  wrote:
>
> But so, when in a thread I receive a private reply that, for some reason 
> (e.g. somewhat rude but/or of public interest and maybe they clicked "Reply" 
> by inadvertance), I feel it should be forwarded to the list (which I have 
> seen done here several times and I don't remember you objecting), how am I 
> supposed to know that they're banned and that I should just ignore them?
>

Sorry, yeah, I probably should have phrased that more gently as you
couldn't really have known.

> how am I supposed to know that they're banned and that I should just ignore 
> them?

This is one of the problems of using email for discussions. Moving
discussions to a better platform has come up repeatedly and I've spent
a lot of time thinking about it.

The very short summary of the result of that thinking is that I think
that any platform needs to be designed to work not just when people
are trying to collaborate on a project, but having very strong
disagreements, but also when under deliberate attack from people who
want to just disrupt all conversations to sabotage a project. It's
something I'm hoping to work on 'soon' ™.

In this particular case, you could probably go and read his blog
https://www.tonymarston.net/php-mysql/index.html and then give an
appropriate amount of attention to his opinions.

cheers
Dan
Ack

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-29 Thread Guilliam Xavier
On Wed, Apr 28, 2021 at 10:18 PM Dan Ackroyd  wrote:

> On Wed, 28 Apr 2021 at 14:30, Guilliam Xavier 
> wrote:
> >
> > Forwarding to the list, and answering:
> >
>
> Please don't do that.
>
> He was blocked from the list for repeatedly derailing conversations.
>
> After someone has been banned from the mailing list, forwarding their
> emails to the list is not a good thing to do.
>

Sorry, I didn't know.

But so, when in a thread I receive a private reply that, for some reason
(e.g. somewhat rude but/or of public interest and maybe they clicked
"Reply" by inadvertance), I feel it should be forwarded to the list (which
I have seen done here several times and I don't remember you objecting),
how am I supposed to know that they're banned and that I should just ignore
them?


> cheers
> Dan
> Ack
>

Regards,

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-28 Thread Dan Ackroyd
On Wed, 28 Apr 2021 at 14:30, Guilliam Xavier  wrote:
>
> Forwarding to the list, and answering:
>

Please don't do that.

He was blocked from the list for repeatedly derailing conversations.

After someone has been banned from the mailing list, forwarding their
emails to the list is not a good thing to do.

cheers
Dan
Ack

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-28 Thread Guilliam Xavier
Re-forwarding to the list (please stop replying to me in private, thanks).
Also re-answering but I will stop there because that's too much digression
for a partial quote of my initial message.

On Wed, Apr 28, 2021 at 5:30 PM Tony Marston 
wrote:

> On 28/04/2021 14:30, Guilliam Xavier wrote:
> > Forwarding to the list, and answering:
> >
> > On Wed, Apr 28, 2021 at 9:51 AM Tony Marston 
> > wrote:
> >
> >> On 27/04/2021 17:22, Guilliam Xavier wrote:
> >>> On Sat, Apr 24, 2021 at 12:55 PM Saif Eddin Gmati <
> azj...@protonmail.com
> >>>
> >>> wrote:
> >>>
> >>>
> >>> To me the first sentence of the RFC is debatable:
> >>>
>  The purpose of inheritance is code reuse, for when you have a class
> that
>  shares common functionality, and you want others to be able to extend
> it
>  and make use of this functionality in their own class.
> >>>
> >>> That sounds like [abstract] base classes, which certainly permit that,
> >> but
> >>> I wouldn't state that "the purpose" of [designing] class hierarchies is
> >>> "code reuse", which can also (better?) be achieved with traits or even
> >>> simply composition
> >>
> >> I completely disagree that the first sentence of that RFC is debatable
> >> as I consider it to be totally accurate. When you use inheritance via
> >> the 'extends' keyword then every method in the superclass is shared by
> >> the subclass. In the subclass you have the option to override the
> >> implementation of any method in the superclass, or you can add new
> >> methods of your own.
> >
> >
> > But does that necessarily mean that "The purpose of inheritance is code
> > reuse"?
>
> Can you show me any description of OOP which says that the purpose of
> inheritance is anything other than code reuse?


I suspect it won't convince you but you can find quotes like: "The point of
inheritance is to take advantage of polymorphic behavior NOT to reuse code,
and people miss that, they see inheritance as a cheap way to add behavior
to a class." (not that I endorse it absolutely, but that's an example of
different opinion).

What other purose could
> it possibly serve?
>

Modeling a problem domain? Enforcing a contract?


> > This superclass may be abstract, but it need not
> >> be. The methods it contains may be abstract, but they need not be.
> >>
> >
> > I didn't say that they need (the brackets meant "optionally"). And does
> it
> > really matter actually?
>
> Yes. If you inherit any abstract methods you are not actually inheriting
> anything. Not only do you have to manually define in the subclass any
> method which is defined as abstract, you also have to provide the
> implementation.
>

My bad, I should have inserted the reply one sentence earlier: I was
referring to "[abstract] base classes" (from my original quote), not
abstract methods. Of course if the goal is to share implementation there
must be concrete methods in the base class...


> >> According to the Gang of Four the way to avoid the problems caused by
> >> the overuse of inheritance is to only inherit from an abstract class,
> >> which is precise what I do. I am famous for having an abstract table
> >> class in my framework which contains hundreds of methods and thousands
> >> of lines of code, and because each of my 400 concrete table classes
> >> inherits from the same abstract table class that is a LOT of code which
> >> is shared. This abstract table class also allows me to use the Template
> >> Method Pattern (which is mentioned in the Gang of Four book) so that all
> >> the invariant methods are defined in the abstract class which means that
> >> each subclass need only contain the variable "hook" methods for which it
> >> needs to provide an implementation.
> >>
> >
> > Well, PHP is flexible. I have seen many combinations of (one or several
> of)
> > interface, [abstract] class, trait, composition... depending on the
> context.
>
> The fact that there are now several ways of reusing code does not
> detract from the original statement that "The purpose of inheritance is
> code reuse".
>

See above, plus a quick web search for things like "inheritance misuse" or
"class SplStack extends SplDoublyLinkedList" I think shows it's a
controversial subject (hence "debatable" at least).


> >> When you say that code reuse can be better achieved with traits or
> >> object composition I have to disagree.
> >
> >
> > I said "also (better?)", not just "better". But one can think "no" to
> > "better?" ;)
> >
>  >
> > Object composition is used only
> >> by those idiots who overuse inheritance,
>
> In the GoF book on design patterns, which was first published in 1995,
> it quite clearly stated that any problems emanating from inheritance
> were causes by its overuse, and that a solution would be to only ever
> inherit from abstract classes.


"class Stack extends AbstractList" is still wrong.

If people are still overusing inheritance
> 25 years later and ignoring the advice given by the Gang of Four then I
> feel justified in calling 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-28 Thread Larry Garfield
On Wed, Apr 28, 2021, at 7:06 AM, Christian Schneider wrote:
> Am 28.04.2021 um 01:00 schrieb Larry Garfield :
> > However!  Classic OOP design patterns are not all that PHP supports, and 
> > that's a good thing.  The "class" construct, for better or worse, is the 
> > syntax for logic objects, value objects, data objects, and control flow 
> > objects (such as Maybe, Either, etc.), plus assorted other patterns that 
> > are not part of the classic OOP canon.  But they're still good and useful 
> > patterns, and often a better model than classic OOP "polymorph all the 
> > things" approaches.
> > 
> > If we were designing PHP from scratch today, I'd argue for having separate 
> > language constructs for funcy-syntax-closures (which is what service 
> > objects are), product types (structs, value objects, all the same thing), 
> > and control flow types.  Many newer languages do differentiate those 
> > better.  That's not where we are, though, so we're stuck with class being 
> > the uber-syntax for anything even slightly interesting from a type 
> > perspective.  So be it, but it does lead to ample confusion about which use 
> > case you're talking about, especially when not everyone is familiar with 
> > all of the different, distinct use cases.
> > 
> > See also: This thread. :-)
> > 
> > Sealed classes are... not really useful at all for service object use 
> > cases.  They are useful for product type and control flow type use cases.
> 
> 
> ... and ...
> 
> Am 28.04.2021 um 09:39 schrieb Pierre :
> > Yeah, final is something, I originally come from the Java world 20 years 
> > back, and it never hit me as something terrible in PHP, on the contrary, I 
> > use it "per default" personally to promote composition over inheritance, 
> > but when I do that I mostly write interface and composition based APIs 
> > which much more flexibility than an open to extension design (TL;DR: I 
> > always give the user an escape route other than inheritance, and document 
> > it).
> 
> Those are good points you are bringing up.
> You're basically saying that classic OOP has outlived itself in many 
> cases - something I agree with - and we need the ability to use other 
> patterns.
> 
> With that in mind I'm not sure if we really want to tack all this 
> functionality on to "class".
> I think it would be better and less confusing to most developers if we 
> were to bite the bullet and try to do it right.
> Especially since my impression is that we only need to tack it on to 
> "class" if there is urgency and personally I'm not feeling it.
> But then again YMMV.
> 
> You convinced me from a -1 to considering abstaining from the vote ;-)

Ha!  Progress. :-P

As I've indicated before, there are two possible paths to an essentially 
similar end goal, both of which have RFCs written but no code written: Sealed 
classes and the ADTs proposal.  Sealed classes is built on, well, classes.  
ADTs are build on enums, which in PHP are themselves built on classes.  In 
practice, some languages do one, some do the other, and I think one or two may 
do both.

For the use cases I can envision, I think either would work.  Sealed classes 
would be a bit more flexible, while Enum-based ADTs would be more compact and 
convenient in the typical case.  There's one or two use cases I'd like to be 
able to implement where ADTs would probably not be sufficient (state machines), 
but then Sealed classes would be annoyingly verbose in those cases, so...

I'm still mostly open to either approach, and not convinced that we need both 
(though I could be convinced, potentially).  In practice, I think I'm good with 
whichever one someone is able to get implemented first, which is always the 
hard part of any proposal.

(Someone else, I forget who, suggested type aliasing as another solution, where 
you'd just have multiple classes and, in effect, type alias a union of those 
classes to a new name and tell people to use that.  I like type aliases, but 
I'm not convinced that's a viable solution in this case.  It's very 
round-about.)

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-28 Thread Guilliam Xavier
Forwarding to the list, and answering:

On Wed, Apr 28, 2021 at 9:51 AM Tony Marston 
wrote:

> On 27/04/2021 17:22, Guilliam Xavier wrote:
> > On Sat, Apr 24, 2021 at 12:55 PM Saif Eddin Gmati  >
> > wrote:
> >
> >
> > To me the first sentence of the RFC is debatable:
> >
> >> The purpose of inheritance is code reuse, for when you have a class that
> >> shares common functionality, and you want others to be able to extend it
> >> and make use of this functionality in their own class.
> >
> > That sounds like [abstract] base classes, which certainly permit that,
> but
> > I wouldn't state that "the purpose" of [designing] class hierarchies is
> > "code reuse", which can also (better?) be achieved with traits or even
> > simply composition
>
> I completely disagree that the first sentence of that RFC is debatable
> as I consider it to be totally accurate. When you use inheritance via
> the 'extends' keyword then every method in the superclass is shared by
> the subclass. In the subclass you have the option to override the
> implementation of any method in the superclass, or you can add new
> methods of your own.


But does that necessarily mean that "The purpose of inheritance is code
reuse"?

This superclass may be abstract, but it need not
> be. The methods it contains may be abstract, but they need not be.
>

I didn't say that they need (the brackets meant "optionally"). And does it
really matter actually?


> According to the Gang of Four the way to avoid the problems caused by
> the overuse of inheritance is to only inherit from an abstract class,
> which is precise what I do. I am famous for having an abstract table
> class in my framework which contains hundreds of methods and thousands
> of lines of code, and because each of my 400 concrete table classes
> inherits from the same abstract table class that is a LOT of code which
> is shared. This abstract table class also allows me to use the Template
> Method Pattern (which is mentioned in the Gang of Four book) so that all
> the invariant methods are defined in the abstract class which means that
> each subclass need only contain the variable "hook" methods for which it
> needs to provide an implementation.
>

Well, PHP is flexible. I have seen many combinations of (one or several of)
interface, [abstract] class, trait, composition... depending on the context.


> When you say that code reuse can be better achieved with traits or
> object composition I have to disagree.


I said "also (better?)", not just "better". But one can think "no" to
"better?" ;)

Object composition is used only
> by those idiots who overuse inheritance,


:/

and there is no evidence that
> traits are "better" than inheritance.
>

By the way, is there evidence to the contrary? (genuine question)


> Inheritance, when used sensibly, is still the best way to share code.
>

Your opinion, maybe not unanimity (nor absolute truth).


> Regards,
>
> Tony Marston
>
>
Regards,

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-28 Thread Christian Schneider
Am 28.04.2021 um 01:00 schrieb Larry Garfield :
> However!  Classic OOP design patterns are not all that PHP supports, and 
> that's a good thing.  The "class" construct, for better or worse, is the 
> syntax for logic objects, value objects, data objects, and control flow 
> objects (such as Maybe, Either, etc.), plus assorted other patterns that are 
> not part of the classic OOP canon.  But they're still good and useful 
> patterns, and often a better model than classic OOP "polymorph all the 
> things" approaches.
> 
> If we were designing PHP from scratch today, I'd argue for having separate 
> language constructs for funcy-syntax-closures (which is what service objects 
> are), product types (structs, value objects, all the same thing), and control 
> flow types.  Many newer languages do differentiate those better.  That's not 
> where we are, though, so we're stuck with class being the uber-syntax for 
> anything even slightly interesting from a type perspective.  So be it, but it 
> does lead to ample confusion about which use case you're talking about, 
> especially when not everyone is familiar with all of the different, distinct 
> use cases.
> 
> See also: This thread. :-)
> 
> Sealed classes are... not really useful at all for service object use cases.  
> They are useful for product type and control flow type use cases.


... and ...

Am 28.04.2021 um 09:39 schrieb Pierre :
> Yeah, final is something, I originally come from the Java world 20 years 
> back, and it never hit me as something terrible in PHP, on the contrary, I 
> use it "per default" personally to promote composition over inheritance, but 
> when I do that I mostly write interface and composition based APIs which much 
> more flexibility than an open to extension design (TL;DR: I always give the 
> user an escape route other than inheritance, and document it).

Those are good points you are bringing up.
You're basically saying that classic OOP has outlived itself in many cases - 
something I agree with - and we need the ability to use other patterns.

With that in mind I'm not sure if we really want to tack all this functionality 
on to "class".
I think it would be better and less confusing to most developers if we were to 
bite the bullet and try to do it right.
Especially since my impression is that we only need to tack it on to "class" if 
there is urgency and personally I'm not feeling it.
But then again YMMV.

You convinced me from a -1 to considering abstaining from the vote ;-)

- Chris

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-28 Thread Pierre

Le 28/04/2021 à 00:25, Christian Schneider a écrit :

The same - "it is more liberty" - could be said about operator overloading, 
multiple inheritance and many other language features which lead to people using them in 
ways / places I consider harmful. So I'd rather not have them in my language of choice.

Yes, I get your point.

Anyway, operator overloading and multiple inheritance raise much more 
complex technical details, and much more specification to be written, 
and induce much more magic in the air !


Sealing a class doesn't induce any change in behavior, doesn't induce 
any functional spec, doesn't hide any runtime flow behind magic, doesn't 
forces to redact and implement some kind of resolution order mechanism 
or hidden magic, it's just a finer variant of the already existing final 
keyword.



I'm not saying the feature is completely useless in the right hands but I think 
it will be misunderstood and promotes bad habits. Think people abusing 
exceptions for flow control.


Any powerful tool can be misused, I mean this argument is real for all 
of: exceptions, switch statements, final methods, traits, basic 
inheritance, magic methods, bit flags, type coercion, etc, etc etc,... I 
think that the sealed classes, by the fact they reduce usability of 
classes themselves is not something that gets promoted, but rather 
something that will be used in edge cases where it makes sense.


Of course, people will always end up, at some point, using it the wrong 
way, but hey, we're all doing open source, community feedback and review 
is the best of all ways to avoid that major libraries or software used 
by many will end up polluting their code with such bad code :)



But then again maybe I'm just traumatized by people putting final all over the 
place in Java back in the days. I'm sure people in 2021 know better than that 
/s ;-)


Yeah, final is something, I originally come from the Java world 20 years 
back, and it never hit me as something terrible in PHP, on the contrary, 
I use it "per default" personally to promote composition over 
inheritance, but when I do that I mostly write interface and composition 
based APIs which much more flexibility than an open to extension design 
(TL;DR: I always give the user an escape route other than inheritance, 
and document it).


Even in my daily work working for client proprietary projects, I always 
write final per default everywhere, so that we spot those changes in 
peer review and have the reflex to ask "why did you extend ? wasn't it 
possible to decorate, write an interface, or fix the bug ?". In that 
regard, for many cases, sealed classes may be something to us, because 
it could fit in our production workflow, not everywhere, (I'd reassure 
you, I'm not going to write "sealed" everywhere) nevertheless it has a 
real added value and meaning when writing business critical code path 
that need extra testing and stability in the long term.


Regards

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Ben Ramsey
> On Apr 27, 2021, at 18:58, David Gebler  wrote:
> 
> Anyway, yeah - I've said my piece(s) and I'm not a voting member so what I
> think doesn't matter to that end. I hope my input on internals discussions
> is not entirely moot, though; just like everyone else I take part because
> I'm very fond of PHP and have an interest in its future. Appreciate those
> who are willing to hear me out.


I wanted to take a moment to say that your voice is important, even if
you’re not a voting member. You’re a user of the language, and that
matters to those who vote. There may be fundamental disagreements here
on the list about the direction of the language, but taking the time to
weigh-in improves these RFCs for the better.

As with many things in life, we have to make compromises to work
together, but please don’t let that discourage you (or anyone else, for
that matter) from voicing concerns over how a proposed feature might
change the way you use the language. Someone else might not have
considered your perspective, and it might bring changes to the RFC or
change someone’s mind about how they’ll vote.

So, keep it up!

Cheers,
Ben


signature.asc
Description: Message signed with OpenPGP


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread David Gebler
Okay, I promise  I'll make this my last word on the thread, for the sake of
my own sanity and at this point, I'm sure that of others - first, I really
appreciate your explanation there for why you consider this RFC a good
thing, so thank you for that. Personally, my objections still stand for in
essence the same reasons as before;

1. In respect of data modelling, you may think you've understood a model
such that its sum is closed, this may even be true for your use case (and
yes, agree both that this is useful and some other languages have better
ways of expressing it) but sometimes, it is only true until it isn't. E.g.
you have said colours are red, green and blue. This is fine until someone
else needs to reason about purple and can't because your data model says
there is no purple.

2. A (non-functional) attribute [or other syntax/convention] for sealed
does not / should not be interpreted as saying "pretty please, don't extend
me", it says "I don't endorse/support this, but if I haven't accounted for
your use case and you're confident you understand your problem, hey, don't
let me stand in your way" - other interpreted languages (Python comes to
mind) use this approach very effectively and their ecosystems are not
automatically riddled with bad models as a result. Indeed PHP is in some
respects unusually strict for an interpreted language (though I am not
saying that is necessarily a bad thing).

3. That there are valid use cases for a language construct does not mean
people will only use it for those cases - I'd go as far as to say they
definitely won't. Annotation in some form is safe in all use cases, fatal
errors aren't. So I stand by the real, primary benefit of these constructs
- delineation of intent boundaries - is achieved without creating a
construct which introduces a new fatal error condition.

Anyway, yeah - I've said my piece(s) and I'm not a voting member so what I
think doesn't matter to that end. I hope my input on internals discussions
is not entirely moot, though; just like everyone else I take part because
I'm very fond of PHP and have an interest in its future. Appreciate those
who are willing to hear me out.

On Wed, Apr 28, 2021 at 12:00 AM Larry Garfield 
wrote:

> On Tue, Apr 27, 2021, at 5:48 PM, David Gebler wrote:
> > On Tue, Apr 27, 2021 at 11:23 PM Larry Garfield 
> > wrote:
> >
> > The two options to prevent such errors are:
> > >
> > > 1. Sealed classes.
> > > 2. Extend Enums into ADTs.
> > >
> >
> > Unless I've misunderstood your example, there is a third option which
> quite
> > possibly prevents the error in a nicer, easier to reason about, more
> > flexible pattern.
> >
> > class Perhaps extends Maybe implements OperatesOnTheValueInterface { ...
> }
>
> If we were dealing with a service object in classic OOP (viz, OOP based on
> classes), then yes, turning the function into a method and using
> polymorphism would be the correct answer, rather than RTTI.
>
> However!  Classic OOP design patterns are not all that PHP supports, and
> that's a good thing.  The "class" construct, for better or worse, is the
> syntax for logic objects, value objects, data objects, and control flow
> objects (such as Maybe, Either, etc.), plus assorted other patterns that
> are not part of the classic OOP canon.  But they're still good and useful
> patterns, and often a better model than classic OOP "polymorph all the
> things" approaches.
>
> If we were designing PHP from scratch today, I'd argue for having separate
> language constructs for funcy-syntax-closures (which is what service
> objects are), product types (structs, value objects, all the same thing),
> and control flow types.  Many newer languages do differentiate those
> better.  That's not where we are, though, so we're stuck with class being
> the uber-syntax for anything even slightly interesting from a type
> perspective.  So be it, but it does lead to ample confusion about which use
> case you're talking about, especially when not everyone is familiar with
> all of the different, distinct use cases.
>
> See also: This thread. :-)
>
> Sealed classes are... not really useful at all for service object use
> cases.  They are useful for product type and control flow type use cases.
>
> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Chase Peeler
On Tue, Apr 27, 2021 at 7:00 PM Larry Garfield 
wrote:

> On Tue, Apr 27, 2021, at 5:48 PM, David Gebler wrote:
> > On Tue, Apr 27, 2021 at 11:23 PM Larry Garfield 
> > wrote:
> >
> > The two options to prevent such errors are:
> > >
> > > 1. Sealed classes.
> > > 2. Extend Enums into ADTs.
> > >
> >
> > Unless I've misunderstood your example, there is a third option which
> quite
> > possibly prevents the error in a nicer, easier to reason about, more
> > flexible pattern.
> >
> > class Perhaps extends Maybe implements OperatesOnTheValueInterface { ...
> }
>
> If we were dealing with a service object in classic OOP (viz, OOP based on
> classes), then yes, turning the function into a method and using
> polymorphism would be the correct answer, rather than RTTI.
>
> However!  Classic OOP design patterns are not all that PHP supports, and
> that's a good thing.  The "class" construct, for better or worse, is the
> syntax for logic objects, value objects, data objects, and control flow
> objects (such as Maybe, Either, etc.), plus assorted other patterns that
> are not part of the classic OOP canon.  But they're still good and useful
> patterns, and often a better model than classic OOP "polymorph all the
> things" approaches.
>
> If we were designing PHP from scratch today, I'd argue for having separate
> language constructs for funcy-syntax-closures (which is what service
> objects are), product types (structs, value objects, all the same thing),
> and control flow types.  Many newer languages do differentiate those
> better.  That's not where we are, though, so we're stuck with class being
> the uber-syntax for anything even slightly interesting from a type
> perspective.  So be it, but it does lead to ample confusion about which use
> case you're talking about, especially when not everyone is familiar with
> all of the different, distinct use cases.
>
> See also: This thread. :-)
>
> Sealed classes are... not really useful at all for service object use
> cases.  They are useful for product type and control flow type use cases.
>
>
And I think that is where our approaches differ. You feel that since sealed
classes are useful for at least one of the ways classes can be used in PHP,
then we should make them available even if that means they end up getting
used with the ways that they don't make sense. My feeling is that we
shouldn't introduce something that would cause restrictions where they
don't make sense just so we can have them where they do.


> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

-- 
Chase Peeler
chasepee...@gmail.com


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Mike Schinkel



> On Apr 27, 2021, at 7:00 PM, Larry Garfield  wrote:
> 
> On Tue, Apr 27, 2021, at 5:48 PM, David Gebler wrote:
>> On Tue, Apr 27, 2021 at 11:23 PM Larry Garfield 
>> wrote:
>> 
>> The two options to prevent such errors are:
>>> 
>>> 1. Sealed classes.
>>> 2. Extend Enums into ADTs.
>>> 
>> 
>> Unless I've misunderstood your example, there is a third option which quite
>> possibly prevents the error in a nicer, easier to reason about, more
>> flexible pattern.
>> 
>> class Perhaps extends Maybe implements OperatesOnTheValueInterface { ... }
> 
> If we were dealing with a service object in classic OOP (viz, OOP based on 
> classes), then yes, turning the function into a method and using polymorphism 
> would be the correct answer, rather than RTTI.
> 
> However!  Classic OOP design patterns are not all that PHP supports, and 
> that's a good thing.  The "class" construct, for better or worse, is the 
> syntax for logic objects, value objects, data objects, and control flow 
> objects (such as Maybe, Either, etc.), plus assorted other patterns that are 
> not part of the classic OOP canon.  But they're still good and useful 
> patterns, and often a better model than classic OOP "polymorph all the 
> things" approaches.
> 
> If we were designing PHP from scratch today, I'd argue for having separate 
> language constructs for funcy-syntax-closures (which is what service objects 
> are), product types (structs, value objects, all the same thing), and control 
> flow types.  Many newer languages do differentiate those better.  That's not 
> where we are, though, so we're stuck with class being the uber-syntax for 
> anything even slightly interesting from a type perspective.

But, are we really, stuck?  

You successfully introduced enumerations.  Why not also data types and control 
flow types?

Just asking for a "friend."


>  So be it, but it does lead to ample confusion about which use case you're 
> talking about, especially when not everyone is familiar with all of the 
> different, distinct use cases.
> 
> See also: This thread. :-)
> 
> Sealed classes are... not really useful at all for service object use cases.  
> They are useful for product type and control flow type use cases.
> 
> --Larry Garfield
> 
> -- 
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
> 

-Mike
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Larry Garfield
On Tue, Apr 27, 2021, at 5:48 PM, David Gebler wrote:
> On Tue, Apr 27, 2021 at 11:23 PM Larry Garfield 
> wrote:
> 
> The two options to prevent such errors are:
> >
> > 1. Sealed classes.
> > 2. Extend Enums into ADTs.
> >
> 
> Unless I've misunderstood your example, there is a third option which quite
> possibly prevents the error in a nicer, easier to reason about, more
> flexible pattern.
> 
> class Perhaps extends Maybe implements OperatesOnTheValueInterface { ... }

If we were dealing with a service object in classic OOP (viz, OOP based on 
classes), then yes, turning the function into a method and using polymorphism 
would be the correct answer, rather than RTTI.

However!  Classic OOP design patterns are not all that PHP supports, and that's 
a good thing.  The "class" construct, for better or worse, is the syntax for 
logic objects, value objects, data objects, and control flow objects (such as 
Maybe, Either, etc.), plus assorted other patterns that are not part of the 
classic OOP canon.  But they're still good and useful patterns, and often a 
better model than classic OOP "polymorph all the things" approaches.

If we were designing PHP from scratch today, I'd argue for having separate 
language constructs for funcy-syntax-closures (which is what service objects 
are), product types (structs, value objects, all the same thing), and control 
flow types.  Many newer languages do differentiate those better.  That's not 
where we are, though, so we're stuck with class being the uber-syntax for 
anything even slightly interesting from a type perspective.  So be it, but it 
does lead to ample confusion about which use case you're talking about, 
especially when not everyone is familiar with all of the different, distinct 
use cases.

See also: This thread. :-)

Sealed classes are... not really useful at all for service object use cases.  
They are useful for product type and control flow type use cases.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread David Gebler
On Tue, Apr 27, 2021 at 11:23 PM Larry Garfield 
wrote:

The two options to prevent such errors are:
>
> 1. Sealed classes.
> 2. Extend Enums into ADTs.
>

Unless I've misunderstood your example, there is a third option which quite
possibly prevents the error in a nicer, easier to reason about, more
flexible pattern.

class Perhaps extends Maybe implements OperatesOnTheValueInterface { ... }


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Christian Schneider
Am 27.04.2021 um 19:19 schrieb Pierre :
> I think that the debate "but if your seal your classes I won't be to extend 
> it" is overrated: it's not the language to chose whether or not the 
> library/software author can seal its classes or not, it's up the 
> library/software author to do its own choice. And in that regard, having 
> "sealed" classes in the language is actually bringing that possibility to the 
> library author, so it's more liberty.


The same - "it is more liberty" - could be said about operator overloading, 
multiple inheritance and many other language features which lead to people 
using them in ways / places I consider harmful. So I'd rather not have them in 
my language of choice.

I'm not saying the feature is completely useless in the right hands but I think 
it will be misunderstood and promotes bad habits. Think people abusing 
exceptions for flow control.

But then again maybe I'm just traumatized by people putting final all over the 
place in Java back in the days. I'm sure people in 2021 know better than that 
/s ;-)

- Chris

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Larry Garfield
On Tue, Apr 27, 2021, at 2:07 PM, Chase Peeler wrote:

> > Sometimes it's helpful to apply a risk perspective the shed some light
> > under hidden assumptions of different arguments. For example, what's
> > the probability and impact of an event that would limit a coder when a
> > library is using a sealed class? And the other way around, what's the
> > probability and impact of an event that would decrease code quality
> > when a sealed class is *not* used (like being able to subclass
> > Maybe/Option even when it "shouldn't" be possible)?
> >
> >
> As someone mentioned above, maybe they want to just add some logging
> capabilities to maybe.
> class MyMaybe extends Maybe {
>   protected $logger;
>   public function setLogger($logger){ $this->logger = $logger; }
>   public function value(){
>  if(null !== $this->logger){ $this->logger->log("getting value"); }
>  return parent::value();
>   }
>  }

That's subtly different than what is being discussed here.  Consider:

class Maybe { ... }

class Some extends Maybe { ... }

class None extends Maybe { ... }

And now assume we have pattern matching in the match expression (just to make 
the following example simpler; it could also be done with instanceof directives 
just as well but it's more verbose):

function operateOnValue(Maybe $m) {
  $val = match($m) is (
Some($v) => $v,
None => $some_default,
  };
  ...
}

This code works on Maybe as defined, with two branches, Some and None.

If you extend Some with your own custom Some, it still works.  This code is 
fine.  Such extension could be prevented by making Some final, but *you can 
already do that today*.

If you want to add another subclass of Maybe, called Perhaps... that function 
will now break, because the nominal contract of Maybe (that it has only two 
variants) has been broken.  As soon as you pass a Perhaps to operateOnValue(), 
the function will fail with an exception.  And there is no way to prevent that 
today.

The two options to prevent such errors are:

1. Sealed classes.
2. Extend Enums into ADTs.

They're different in a few key ways, but both address the same problem space 
and would render operateOnValue() safer against errors, because its developer 
can know, by definition, that it can handle all possible variants of Maybe.  
(That is, it's a total function over Maybe.)

A comment (by whatever syntax) saying "pretty please don't extend Maybe" is 
worth the executable code it generates (which is to say, None).

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Levi Morrison via internals
On Tue, Apr 27, 2021 at 12:12 PM David Gebler  wrote:
>
>
>
> On Tue, Apr 27, 2021 at 6:56 PM Levi Morrison  
> wrote:
>>
>> I think the conversation on final classes being "bad" has gone on long
>> enough. You don't like final, and you don't want to see more features
>> like it being added, such as sealed. Point taken. Now please stop
>> dominating the discussion, thank you.
>
>
> In a thread of around 50 messages, I have posted six of them, half of which 
> are addressing direct replies to the other half. I have also not treated 
> anyone rudely, disrespectfully, or  gone off-topic. That is not dominating, 
> it is healthy discussion which should be encouraged. If you don't want to 
> read my contributions, I'm sure you can filter them.
>
> Nonetheless, you may be pleased to know as far as I'm concerned, I have fully 
> expressed my view and reasoning on this RFC and have nothing further I wish 
> to add to the conversation.

David,

Sorry, I did not mean you specifically, I mean the collective you as
in "you all." Sorry for the ambiguity.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Mike Schinkel

> On Apr 27, 2021, at 3:07 PM, Chase Peeler  wrote:
> 
> As someone mentioned above, maybe they want to just add some logging
> capabilities to maybe.
> class MyMaybe extends Maybe {
>  protected $logger;
>  public function setLogger($logger){ $this->logger = $logger; }
>  public function value(){
> if(null !== $this->logger){ $this->logger->log("getting value"); }
> return parent::value();
>  }
> }

That is one argument. But maybe that argument points to the need for a 
different feature, one that could be considered for PHP instead of limiting the 
freedom of the library/framework author to decide how their code will be used?

We could add an Events feature that would allow users of a class to run a 
closure before or after every time a class' methods are run?  People often 
suggest that attributes can be used to implement such features but then 
attributes can only be added by the author of the class, not injected by users 
of the class.

Imagine if something like the following existed (I just spitballed the syntax 
as a straw man suggestion; I doubt an actual events feature would look much 
like this after requirements were fleshed out):

/* 
 * Attach an event to run *after* every time the Maybe class was instantiated
 */
\PHP\Events::after( [ Maybe::class, "__construct" ], func($context){
// Attach a property to the instance that would only be visible inside of 
events
$context->logger = MyLogger::get();
})

/* 
 * Attach an event to run *before* every time the value() method was called an 
a Maybe instance
 */
\PHP\Events::before( [ Maybe::class, "value" ], func($context){
// Call log() on the attached $logger property
$context->logger->log("getting value");
})

/* 
 * Your logger class
 */
class MyLogger {
   private static $logger;
   public static function set($logger){
 self::$logger = $logger;
   }
   public static function get(){
 if (!isset(self::$logger)) {
self::$logger = new MyLogger();
 }
 return $logger;
   }
   public static function log($msg){
 printf( "$1\n", $msg );
   }
}

/* 
 * Example usage code
 */
$m = new Maybe(1)
echo $m->value();   // echos "getting value\n1"


In my view this would be more consistent with the open-closed principle of 
S.O.L.I.D. because it would allow a developer to augment classes in libraries 
and frameworks that hardcode instantiate — do not just dependency injection — 
something you cannot do with mere subclassing.

I know this suggestion is off-topic for this thread, but I introduce to point 
out at least some of the objections to `sealed` could addressed better by new 
language features.  

SO IF people are interested in discussing this specific language feature more, 
PLEASE break this off into a different thread.

-Mike
P.S. Also, I admit I did what I hate when other people do it; I focused on your 
example that you used to illustrate a general principle and I addressed that 
example only, not your general concern. But I only did so because other 
features would better address that specific example.  

Do you have other examples that would illustrate why you might want to extend a 
Maybe class that could not be handled with events?



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Chase Peeler
On Tue, Apr 27, 2021 at 2:57 PM Olle Härstedt 
wrote:

> 2021-04-27 20:17 GMT+02:00, Chase Peeler :
> > On Tue, Apr 27, 2021 at 1:56 PM Levi Morrison via internals <
> > internals@lists.php.net> wrote:
> >
> >> I think the conversation on final classes being "bad" has gone on long
> >> enough. You don't like final, and you don't want to see more features
> >> like it being added, such as sealed. Point taken. Now please stop
> >> dominating the discussion, thank you.
> >>
> >>
> > I think the legitimacy of final/sealed classes goes to the heart of this
> > RFC. As long as people are going to discuss it and bring up counter
> points,
> > then I think asking someone to stop defending their view is a bit out of
> > line.
> >
> > That being said, David has never said he is against developers being able
> > to annotate their classes as being final or sealed. He is just against
> the
> > engine enforcing such requirements. On this I agree. I understand that
> > other languages support this concept - and frankly, I don't care. The
> > flexibility that PHP offers has always been one of its greatest strengths
> > and this just further erodes that.
> >
> >
> >> --
> >> PHP Internals - PHP Runtime Development Mailing List
> >> To unsubscribe, visit: https://www.php.net/unsub.php
> >>
> >>
> >
> > --
> > Chase Peeler
> > chasepee...@gmail.com
> >
>
> Sometimes it's helpful to apply a risk perspective the shed some light
> under hidden assumptions of different arguments. For example, what's
> the probability and impact of an event that would limit a coder when a
> library is using a sealed class? And the other way around, what's the
> probability and impact of an event that would decrease code quality
> when a sealed class is *not* used (like being able to subclass
> Maybe/Option even when it "shouldn't" be possible)?
>
>
As someone mentioned above, maybe they want to just add some logging
capabilities to maybe.
class MyMaybe extends Maybe {
  protected $logger;
  public function setLogger($logger){ $this->logger = $logger; }
  public function value(){
 if(null !== $this->logger){ $this->logger->log("getting value"); }
 return parent::value();
  }
 }


> If the probability of such an event is high, but the impact to overall
> code quality is low, the risk is also considered low. (Example: Just
> create your own Maybe class. Of course harder with more elaborate
> classes, you don't want to copy-paste an entire library. And the other
> way, extending Maybe is a very local thing to do and doesn't hurt the
> library itself.)
>
>
Copy/pasting Maybe into my own MyMaybe class isn't going to be a valid
option if I encounter something like

function(Maybe $maybe){...}

If I can subclass Maybe, then it will work. If MyMaybe is a totally
different class, though, it won't.



> When both probability and impact are uncertain, it will make it harder
> to create consensus, and will make arguments more emotional or
> heuristic. When risk is low and the benefit high (and clear),
> consensus is easy.
>
> Olle
>


-- 
Chase Peeler
chasepee...@gmail.com


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Olle Härstedt
2021-04-27 20:17 GMT+02:00, Chase Peeler :
> On Tue, Apr 27, 2021 at 1:56 PM Levi Morrison via internals <
> internals@lists.php.net> wrote:
>
>> I think the conversation on final classes being "bad" has gone on long
>> enough. You don't like final, and you don't want to see more features
>> like it being added, such as sealed. Point taken. Now please stop
>> dominating the discussion, thank you.
>>
>>
> I think the legitimacy of final/sealed classes goes to the heart of this
> RFC. As long as people are going to discuss it and bring up counter points,
> then I think asking someone to stop defending their view is a bit out of
> line.
>
> That being said, David has never said he is against developers being able
> to annotate their classes as being final or sealed. He is just against the
> engine enforcing such requirements. On this I agree. I understand that
> other languages support this concept - and frankly, I don't care. The
> flexibility that PHP offers has always been one of its greatest strengths
> and this just further erodes that.
>
>
>> --
>> PHP Internals - PHP Runtime Development Mailing List
>> To unsubscribe, visit: https://www.php.net/unsub.php
>>
>>
>
> --
> Chase Peeler
> chasepee...@gmail.com
>

Sometimes it's helpful to apply a risk perspective the shed some light
under hidden assumptions of different arguments. For example, what's
the probability and impact of an event that would limit a coder when a
library is using a sealed class? And the other way around, what's the
probability and impact of an event that would decrease code quality
when a sealed class is *not* used (like being able to subclass
Maybe/Option even when it "shouldn't" be possible)?

If the probability of such an event is high, but the impact to overall
code quality is low, the risk is also considered low. (Example: Just
create your own Maybe class. Of course harder with more elaborate
classes, you don't want to copy-paste an entire library. And the other
way, extending Maybe is a very local thing to do and doesn't hurt the
library itself.)

When both probability and impact are uncertain, it will make it harder
to create consensus, and will make arguments more emotional or
heuristic. When risk is low and the benefit high (and clear),
consensus is easy.

Olle

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Pierre

Le 27/04/2021 à 19:51, David Gebler a écrit :

I don't think at any moment that any of the
people here really meant that, but it it's fundamentally what this
argument does: it says that some conventions are by nature bad and the
language should enforce people not to write code like this.

I think the language should not enforce any practice, convention or code
The sealed feature does not enforce anything. It brings a new tool in 
already quite furnished toolbox. It doesn't force you to use it (and 
besides I think it's a good tool, but as I said, I can live without).

Some conventions may or may not be bad by nature but that's not the
argument I'm making, at all. The language enforcing one person's
preferences over another's is exactly what you are advocating and I am
cautioning against.


It's not enforcing one person's preference over another's, people should 
be able to seal whatever they want to seal in their own code. I repeat, 
their code, not yours. If you don't like another person's code because 
you can't override a class, then fork it or use another library. And 
beside, I doubt that people will use it so widely that it'll prevent you 
from doing anything good. Or if they do so, they are probably not 
writing a so good piece of software (beware, subjectivity in the last 
sentence).


By preventing so hard such feature to be included on this sole argument, 
you are actually dictating your own preference, not the other way around.


I think that sealed class usage remains an edge case, and it's basically 
meant to avoid users to shooting themselves in the foot and open the 
discussion when they think it's not a good choice.



I think this point/argument should be banned from this discussion.

Given the behaviour we're talking about is literally the change proposed in
the RFC, I find this a very strange take.


I don't think it is, it's not how I understood it at the very least.

Please don't take anything I said as being disrespectful (I'm not a 
native english speaker and sometime I do not measure my own words), on 
the contrary it's an interesting discussion.


Regards,

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Chase Peeler
On Tue, Apr 27, 2021 at 1:56 PM Levi Morrison via internals <
internals@lists.php.net> wrote:

> I think the conversation on final classes being "bad" has gone on long
> enough. You don't like final, and you don't want to see more features
> like it being added, such as sealed. Point taken. Now please stop
> dominating the discussion, thank you.
>
>
I think the legitimacy of final/sealed classes goes to the heart of this
RFC. As long as people are going to discuss it and bring up counter points,
then I think asking someone to stop defending their view is a bit out of
line.

That being said, David has never said he is against developers being able
to annotate their classes as being final or sealed. He is just against the
engine enforcing such requirements. On this I agree. I understand that
other languages support this concept - and frankly, I don't care. The
flexibility that PHP offers has always been one of its greatest strengths
and this just further erodes that.


> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

-- 
Chase Peeler
chasepee...@gmail.com


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread David Gebler
On Tue, Apr 27, 2021 at 6:56 PM Levi Morrison 
wrote:

> I think the conversation on final classes being "bad" has gone on long
> enough. You don't like final, and you don't want to see more features
> like it being added, such as sealed. Point taken. Now please stop
> dominating the discussion, thank you.
>

In a thread of around 50 messages, I have posted six of them, half of which
are addressing direct replies to the other half. I have also not treated
anyone rudely, disrespectfully, or  gone off-topic. That is not dominating,
it is healthy discussion which should be encouraged. If you don't want to
read my contributions, I'm sure you can filter them.

Nonetheless, you may be pleased to know as far as I'm concerned, I have
fully expressed my view and reasoning on this RFC and have nothing further
I wish to add to the conversation.


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Levi Morrison via internals
I think the conversation on final classes being "bad" has gone on long
enough. You don't like final, and you don't want to see more features
like it being added, such as sealed. Point taken. Now please stop
dominating the discussion, thank you.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread David Gebler
On Tue, Apr 27, 2021 at 6:19 PM Pierre  wrote:

> Le 27/04/2021 à 18:46, David Gebler a écrit :
> > What's being proposed in the RFC is a functional change to the language
> > whereby attempting to extend a class designated as sealed to a
> > non-specified child results in a fatal error.
>
> It's not a functional change to the language, well, it is a new feature,
> but it's actually not changing any paradigm in the language or the
> engine. People will continue to write the same code, and people that
> want to use it for some library or customer project internal purpose may
> use it.
>

If you introduce it, people will use it and the people who use their code
will (no pun intended) inherit it. So the idea that no one is obligated to
use this pattern if they don't want to is at least de facto untrue.


>
> > Now that is not a benefit in itself, it is merely a description of the
> > proposed change. My question is who or what benefits from this change?
> And
> > I look at this way:
> >
> > 1. The language engine doesn't benefit, since unlike some compiled
> > languages, there is no indication here it will result in improved opcode
> > sequences.
> >
> > 2. The author of code doesn't benefit, to any extent greater than they
> > would by using an attribute or other metadata to indicate their
> intentions,
> > because if someone else comes along, installs their library and creates
> > problems for themselves by extending some concrete type in a manner which
> > was not intended, the author's obligation to them is zero. If improperly
> > inheriting or otherwise misusing code creates a problem for a consumer,
> > it's the consumer's mess to sort out.
>
> I think that the debate "but if your seal your classes I won't be to
> extend it" is overrated: it's not the language to chose whether or not
> the library/software author can seal its classes or not, it's up the
> library/software author to do its own choice.


Agree, which is precisely why I challenge there is any need for it to be
enforced in the language with a fatal error.


> And in that regard, having
> "sealed" classes in the language is actually bringing that possibility
> to the library author, so it's more liberty.
>
> By design, by convention, in any of a company or an open source software
> community, it can be legit to explicitly hard-seal stuff, for blocking
> users when they are doing it wrong, if for example by attempting to
> inherit they will break other existing piece code, for example. There's
> many scenarios where it's legit to seal classes, and it can be a good
> practice also (depend on your practices I guess).
>
> But if sealing means "you who want to change a behavior, you need to fix
> other things deep in the code before being able to do that" then it's
> good (and it's one of the use cases of sealing).
>
> So each time someone use the "but we won't be able to legitimately
> extend your class" he's basically saying that people that do put very
> thorough and strict conventions in their own code are wrong by nature
> and don't understand what is good. It's almost an insult - please don't
> misunderstand what I say,


I entirely understand and appreciate your view here, but it's no more
insulting than to say to your users "You are wrong by nature; I know your
use-case better than you do (without even seeing it or having knowledge of
it) and there is no legitimate reason for you to ever extend my class"


> I don't think at any moment that any of the
> people here really meant that, but it it's fundamentally what this
> argument does: it says that some conventions are by nature bad and the
> language should enforce people not to write code like this.

I think the language should not enforce any practice, convention or code
> style, it must remain neutral considering people's whereabouts,
> workflows or practices. If one's want to seal his or her class, let him
> or her do it.
>

Some conventions may or may not be bad by nature but that's not the
argument I'm making, at all. The language enforcing one person's
preferences over another's is exactly what you are advocating and I am
cautioning against.


>
> I think this point/argument should be banned from this discussion.


Given the behaviour we're talking about is literally the change proposed in
the RFC, I find this a very strange take.


>
> Sealed classes are good under some conditions, maybe bad under others,
> that's not the point, it's not about discussing each developer's,
> community's or company's own conventions, but about is it OK technically
> to add this feature to the language, and will it be or not a maintenance
> burden, and finally will it actually break millions of lines of existing
> code.
>
> I'm inclined to say yes, it is good to add this feature, and I'm
> skeptical about the fact that it would break existing code (except for
> people that named their classes "Permits"), there's many use cases I
> wish I had it in the past. I can live with it, but sometime, it 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Pierre

Le 27/04/2021 à 18:46, David Gebler a écrit :

What's being proposed in the RFC is a functional change to the language
whereby attempting to extend a class designated as sealed to a
non-specified child results in a fatal error.


It's not a functional change to the language, well, it is a new feature, 
but it's actually not changing any paradigm in the language or the 
engine. People will continue to write the same code, and people that 
want to use it for some library or customer project internal purpose may 
use it.



Now that is not a benefit in itself, it is merely a description of the
proposed change. My question is who or what benefits from this change? And
I look at this way:

1. The language engine doesn't benefit, since unlike some compiled
languages, there is no indication here it will result in improved opcode
sequences.

2. The author of code doesn't benefit, to any extent greater than they
would by using an attribute or other metadata to indicate their intentions,
because if someone else comes along, installs their library and creates
problems for themselves by extending some concrete type in a manner which
was not intended, the author's obligation to them is zero. If improperly
inheriting or otherwise misusing code creates a problem for a consumer,
it's the consumer's mess to sort out.


I think that the debate "but if your seal your classes I won't be to 
extend it" is overrated: it's not the language to chose whether or not 
the library/software author can seal its classes or not, it's up the 
library/software author to do its own choice. And in that regard, having 
"sealed" classes in the language is actually bringing that possibility 
to the library author, so it's more liberty.


By design, by convention, in any of a company or an open source software 
community, it can be legit to explicitly hard-seal stuff, for blocking 
users when they are doing it wrong, if for example by attempting to 
inherit they will break other existing piece code, for example. There's 
many scenarios where it's legit to seal classes, and it can be a good 
practice also (depend on your practices I guess).


But if sealing means "you who want to change a behavior, you need to fix 
other things deep in the code before being able to do that" then it's 
good (and it's one of the use cases of sealing).


So each time someone use the "but we won't be able to legitimately 
extend your class" he's basically saying that people that do put very 
thorough and strict conventions in their own code are wrong by nature 
and don't understand what is good. It's almost an insult - please don't 
misunderstand what I say, I don't think at any moment that any of the 
people here really meant that, but it it's fundamentally what this 
argument does: it says that some conventions are by nature bad and the 
language should enforce people not to write code like this.


I think the language should not enforce any practice, convention or code 
style, it must remain neutral considering people's whereabouts, 
workflows or practices. If one's want to seal his or her class, let him 
or her do it.


I think this point/argument should be banned from this discussion. 
Sealed classes are good under some conditions, maybe bad under others, 
that's not the point, it's not about discussing each developer's, 
community's or company's own conventions, but about is it OK technically 
to add this feature to the language, and will it be or not a maintenance 
burden, and finally will it actually break millions of lines of existing 
code.


I'm inclined to say yes, it is good to add this feature, and I'm 
skeptical about the fact that it would break existing code (except for 
people that named their classes "Permits"), there's many use cases I 
wish I had it in the past. I can live with it, but sometime, it could be 
the right tool.


Regards,

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Chase Peeler
On Tue, Apr 27, 2021 at 12:47 PM David Gebler  wrote:

> Still, it remains that one could have a legitimate, justifiable reason to
> extend Maybe / some other example, which was not foreseen by its author and
> is prevented by sealed as a keyword despite the fact this inheritance,
> correctly implemented, would not break anything, not define an impossible
> state and not violate anything except the library author's own (limited)
> imagination of how their code ought to be used.
>
> Note in respect of the point people have raised about attributes and my own
> previous comments, I am not advocating any Sealed attribute is added to the
> language as a functional change or embedded language by the backdoor, I am
> merely saying *you* as some class's author can add an attribute, right now,
> to indicate that you consider the class sealed - and an IDE / automated
> tooling could understand it and warn a user there is a risk to violating
> it.
>
> What's being proposed in the RFC is a functional change to the language
> whereby attempting to extend a class designated as sealed to a
> non-specified child results in a fatal error.
>
> Now that is not a benefit in itself, it is merely a description of the
> proposed change. My question is who or what benefits from this change? And
> I look at this way:
>
> 1. The language engine doesn't benefit, since unlike some compiled
> languages, there is no indication here it will result in improved opcode
> sequences.
>
> 2. The author of code doesn't benefit, to any extent greater than they
> would by using an attribute or other metadata to indicate their intentions,
> because if someone else comes along, installs their library and creates
> problems for themselves by extending some concrete type in a manner which
> was not intended, the author's obligation to them is zero. If improperly
> inheriting or otherwise misusing code creates a problem for a consumer,
> it's the consumer's mess to sort out.
>
> 3. The consumer of code doesn't benefit, because if they didn't intend to
> inherit from a sealed, concrete class, it being sealed makes no difference.
> But if they did - and had a legitimate reason to do so - they are now
> forced to fork, proxy or otherwise work around this artificial restriction
> (which they can easily do, by the way, language keyword or none). In any
> valid use case, this can distinctly and only be a disadvantage to them.
>
> Someone - Larry I think - said something to the effect of this isn't about
> restricting your users as an author from doing something you think they
> shouldn't, and that it's about more completely defining problem spaces at
> language level. I respectfully am not convinced. When we look at features
> like enums and stronger typing, we can see distinct benefits in how as
> users of PHP we can model better and write better, more effective and more
> efficient code.
>
> But in the case of sealed and the context of PHP, you cannot model your
> problem space this way better than you can with an attribute or other means
> of annotating metadata. I can certainly agree such metadata is an important
> part and valuable tool for improved modeling, but making it a keyword and
> throwing a fatal error if your limited intentions (which do not predict all
> possible use cases) are violated is merely constraining users from being
> able to do something for its own sake. While there is a legitimate argument
> that serves to "syntactically make certain invalid states impossible", it
> does the same for any valid states you didn't envision.
>
> I'm maybe even inclined to suggest the desire to make a class sealed really
> smells like you want to be using abstract classes and/or interfaces.
>
> To the greatest extent which is practical, my preference is to enable other
> developers rather than constrain them (subject to the caveat I will not
> help them if they do something silly or irresponsible with my code on their
> own volition) - I don't believe the "weirdness" exceptions PHP makes
> internally for things like Throwable or Traversable are good reasons to
> extend this to the language level.
>
>
>
I totally agree with everything said above.

I will add that while I don't support the idea of sealed classes in any
way, were it to be implemented, I agree that implementing it via
compiler/engine enforced attributes is not the way to do it, echoing Dan's
reasoning from earlier.


>
> On Tue, 27 Apr 2021, 16:05 Guilliam Xavier, 
> wrote:
>
> > Hi,
> >
> > On Mon, Apr 26, 2021 at 9:54 AM Christian Schneider <
> cschn...@cschneid.com
> > >
> > wrote:
> >
> > > Am 25.04.2021 um 05:47 schrieb Larry Garfield  >:
> > > ...
> > > > sealed class Maybe permits Some, None {
> > > ...
> > > > }
> > > >
> > > > final class None extends Maybe {}
> > >
> > > This is exactly the thing I'm worried about.
> > >
> > > Say I want to add something like logging to the None type.
> > > Now your sealed and final classes prevent me from defining MyNone
> > > extending None 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread David Gebler
Still, it remains that one could have a legitimate, justifiable reason to
extend Maybe / some other example, which was not foreseen by its author and
is prevented by sealed as a keyword despite the fact this inheritance,
correctly implemented, would not break anything, not define an impossible
state and not violate anything except the library author's own (limited)
imagination of how their code ought to be used.

Note in respect of the point people have raised about attributes and my own
previous comments, I am not advocating any Sealed attribute is added to the
language as a functional change or embedded language by the backdoor, I am
merely saying *you* as some class's author can add an attribute, right now,
to indicate that you consider the class sealed - and an IDE / automated
tooling could understand it and warn a user there is a risk to violating
it.

What's being proposed in the RFC is a functional change to the language
whereby attempting to extend a class designated as sealed to a
non-specified child results in a fatal error.

Now that is not a benefit in itself, it is merely a description of the
proposed change. My question is who or what benefits from this change? And
I look at this way:

1. The language engine doesn't benefit, since unlike some compiled
languages, there is no indication here it will result in improved opcode
sequences.

2. The author of code doesn't benefit, to any extent greater than they
would by using an attribute or other metadata to indicate their intentions,
because if someone else comes along, installs their library and creates
problems for themselves by extending some concrete type in a manner which
was not intended, the author's obligation to them is zero. If improperly
inheriting or otherwise misusing code creates a problem for a consumer,
it's the consumer's mess to sort out.

3. The consumer of code doesn't benefit, because if they didn't intend to
inherit from a sealed, concrete class, it being sealed makes no difference.
But if they did - and had a legitimate reason to do so - they are now
forced to fork, proxy or otherwise work around this artificial restriction
(which they can easily do, by the way, language keyword or none). In any
valid use case, this can distinctly and only be a disadvantage to them.

Someone - Larry I think - said something to the effect of this isn't about
restricting your users as an author from doing something you think they
shouldn't, and that it's about more completely defining problem spaces at
language level. I respectfully am not convinced. When we look at features
like enums and stronger typing, we can see distinct benefits in how as
users of PHP we can model better and write better, more effective and more
efficient code.

But in the case of sealed and the context of PHP, you cannot model your
problem space this way better than you can with an attribute or other means
of annotating metadata. I can certainly agree such metadata is an important
part and valuable tool for improved modeling, but making it a keyword and
throwing a fatal error if your limited intentions (which do not predict all
possible use cases) are violated is merely constraining users from being
able to do something for its own sake. While there is a legitimate argument
that serves to "syntactically make certain invalid states impossible", it
does the same for any valid states you didn't envision.

I'm maybe even inclined to suggest the desire to make a class sealed really
smells like you want to be using abstract classes and/or interfaces.

To the greatest extent which is practical, my preference is to enable other
developers rather than constrain them (subject to the caveat I will not
help them if they do something silly or irresponsible with my code on their
own volition) - I don't believe the "weirdness" exceptions PHP makes
internally for things like Throwable or Traversable are good reasons to
extend this to the language level.



On Tue, 27 Apr 2021, 16:05 Guilliam Xavier, 
wrote:

> Hi,
>
> On Mon, Apr 26, 2021 at 9:54 AM Christian Schneider  >
> wrote:
>
> > Am 25.04.2021 um 05:47 schrieb Larry Garfield :
> > ...
> > > sealed class Maybe permits Some, None {
> > ...
> > > }
> > >
> > > final class None extends Maybe {}
> >
> > This is exactly the thing I'm worried about.
> >
> > Say I want to add something like logging to the None type.
> > Now your sealed and final classes prevent me from defining MyNone
> > extending None even though it would be 100% compatible with None.
> >
>
> I just want to note that this has nothing to do with Maybe made sealed
> (which seems legit), only with None made final (which... could be debated,
> but unrelated to the RFC at hand).
>
> Regards,
>
> --
> Guilliam Xavier
>


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Guilliam Xavier
On Sat, Apr 24, 2021 at 12:55 PM Saif Eddin Gmati 
wrote:

> Hello Internals,
>
> I'm sending this email to open discussion about sealed classes,
> interfaces, and traits feature for PHP 8.1.
>
> I have create a Draft RFC here: https://wiki.php.net/rfc/sealed_classes
>
> A major concern for few people have been the syntax, in which it
> introduces 2 new keywords into the languages, therefor, i have added a
> section about alternative syntax which could be used to avoid this problem.
>
> Regards,
>
> Saif.
>

Hello,

To me the first sentence of the RFC is debatable:

> The purpose of inheritance is code reuse, for when you have a class that
shares common functionality, and you want others to be able to extend it
and make use of this functionality in their own class.

That sounds like [abstract] base classes, which certainly permit that, but
I wouldn't state that "the purpose" of [designing] class hierarchies is
"code reuse", which can also (better?) be achieved with traits or even
simply composition
(by the way, the introduction then mentions that "PHP has the `Throwable`
interface, which defines common functionality between `Error` and
`Exception` and is implemented by both", but there is no "code reuse" in an
interface).

I also agree with others that Shape is probably not a good example, and the
ResultInterface example feels like an enum/ADT (and the FilesystemTrait
example I guess is to replace `@internal` phpDoc).

I'm not saying that this RFC is bad, but probably not as convincing as it
could be.

Regards,

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Guilliam Xavier
Hi,

On Mon, Apr 26, 2021 at 9:54 AM Christian Schneider 
wrote:

> Am 25.04.2021 um 05:47 schrieb Larry Garfield :
> ...
> > sealed class Maybe permits Some, None {
> ...
> > }
> >
> > final class None extends Maybe {}
>
> This is exactly the thing I'm worried about.
>
> Say I want to add something like logging to the None type.
> Now your sealed and final classes prevent me from defining MyNone
> extending None even though it would be 100% compatible with None.
>

I just want to note that this has nothing to do with Maybe made sealed
(which seems legit), only with None made final (which... could be debated,
but unrelated to the RFC at hand).

Regards,

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Pierre

Le 27/04/2021 à 15:21, Dan Ackroyd a écrit :

On Sat, 24 Apr 2021 at 15:03, Benjamin Eberlei  wrote:

There is a much less invasive way to add new keywords/flags
to functions by using attributes.

Imho this decouples new features from the language and reduces the "risk"
of adding them to the language.

I think I disagree with this very strongly, and plan* to vote against
any RFC that embeds another language in annotations.**

It might be quicker, easier, and more seductive to implement language
level features in them, but it is a massive trade-off in making code
hard to reason about.


That should increase the likeliness of it
getting accepted in my opinion.

This can also be pronounced as "makes it more likely to slip bad ideas
in core without thinking them through fully".

My experience of annotations being used as an embedded language is
Java, and it's one of the reasons why I no longer use that language.

Not only is code with many lines of annotations hard to read, it
results in behaviour that is very hard to reason about. I literally
spent 40 hours (spread over the course of 5 weeks), trying to figure
out this bug https://stackoverflow.com/q/9072749/778719 . If my
colleague hadn't been able to tell me the answer, the only way I could
have debugged the problem myself is using a bytecode level debugger,
to step through the internal details of what was happening.

I'd prefer it if we didn't repeat (what I consider to be) the mistakes of Java.

cheers
Dan
Ack


Hello,

Yes, after reading a few answers I changed my mind and I do agree with 
you know, this is a language feature and should be in the language 
syntax and not in attributes.


Regards,

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-27 Thread Dan Ackroyd
On Sat, 24 Apr 2021 at 15:03, Benjamin Eberlei  wrote:
>
> There is a much less invasive way to add new keywords/flags
> to functions by using attributes.
>
> Imho this decouples new features from the language and reduces the "risk"
> of adding them to the language.

I think I disagree with this very strongly, and plan* to vote against
any RFC that embeds another language in annotations.**

It might be quicker, easier, and more seductive to implement language
level features in them, but it is a massive trade-off in making code
hard to reason about.

> That should increase the likeliness of it
> getting accepted in my opinion.

This can also be pronounced as "makes it more likely to slip bad ideas
in core without thinking them through fully".

My experience of annotations being used as an embedded language is
Java, and it's one of the reasons why I no longer use that language.

Not only is code with many lines of annotations hard to read, it
results in behaviour that is very hard to reason about. I literally
spent 40 hours (spread over the course of 5 weeks), trying to figure
out this bug https://stackoverflow.com/q/9072749/778719 . If my
colleague hadn't been able to tell me the answer, the only way I could
have debugged the problem myself is using a bytecode level debugger,
to step through the internal details of what was happening.

I'd prefer it if we didn't repeat (what I consider to be) the mistakes of Java.

cheers
Dan
Ack

* possibly with the exception of optimization annotations e.g. 'memoize'.

** "From a language design perspective, annotations form a
mini-language embedded in Java" -
https://blog.softwaremill.com/the-case-against-annotations-4b2fb170ed67
Though probably most of the other links from "java annotations are
crap" are also appropriate.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Christian Schneider
Am 26.04.2021 um 14:18 schrieb Ilija Tovilo :
> The point of sealed type is to fix the number of subclasses a given
> type can have, which means you can handle a value by type (as that
> list is not finite). Code that handles Optional values could look like
> this:
> 
> ```
> if ($option instanceof Option\None) {
>throw new Exception();
> }
> 
> // We now know the value is a Some
> var_dump($option->value);
> ```

I really hope that's *not* the way people will use the Maybe type

> If you suddenly provide your own version of None the code above will
> break.

... but no, it wouldn't break, as MyNone extends None, so instanceof would 
still work.

> To most people it's obvious that you can't add new cases to an
> existing enum.

The RFC does not mention data classes (at least not explicitly), it talks about 
sharing common functionality.
So I think you're somewhat moving the goal posts.
If you want to limit Enums only then I would have to reconsider, but we were 
talking about generic classes AFAIK.

> It doesn't sound sensible to add logging to a data
> class. That's something that belongs into a hook or service of some
> kind.

You're again making assumption about what's sensible for the user of a library, 
that's the mind-set I would like to avoid.

> People might also want to use sealed for behavioral classes, the use
> case here is the same as final. Final is not here to make your life
> harder. It's here to make the lives of the library maintainers easier.

First of all: Yes, I'm no fan of final either.
I've encountered enough examples where it *did* make my life harder.
And as a library writer myself I value the user experience higher than the 
library developer work because there are (hopefully) a lot more users than 
developers.

> If they have to reason about every way a method could be overridden,
> every change in the library would become more risky, require more
> thought and more frequent major version updates.

A properly designed API should be simple and stable enough to not need this 
kind of safe-guards.
Overly complicated, cathedral-style frameworks might yearn for it but I think 
it's addressing the symptoms, not the cause (-:C

> This means more work and less features for you, too.


That kind of argument reminds me of people saying that user tracking is a good 
thing because I get to see more relevant advertisement.
You're a good sales-man though, I give you that, but you haven't convinced me 
yet ;-)

- Chris



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Ilija Tovilo
Hi Christian

On Mon, Apr 26, 2021 at 9:54 AM Christian Schneider
 wrote:
>
> Am 25.04.2021 um 05:47 schrieb Larry Garfield :
> > In practice, I think all of the use cases for sealed classes are ADT-esque. 
> >  As I noted before, combining sealed classes with Nikita's 
> > new-in-expressions RFC would allow for this (also using my short-functions 
> > RFC for this example, although that's a nice-to-have):
> >
> > sealed class Maybe permits Some, None {
>
> ...
>
> > }
> >
> > final class None extends Maybe {}
>
>
>
> This is exactly the thing I'm worried about.
>
> Say I want to add something like logging to the None type.
> Now your sealed and final classes prevent me from defining MyNone extending 
> None even though it would be 100% compatible with None. Just because *you* 
> deemed that useless or wrong.

The point of sealed type is to fix the number of subclasses a given
type can have, which means you can handle a value by type (as that
list is not finite). Code that handles Optional values could look like
this:

```
if ($option instanceof Option\None) {
throw new Exception();
}

// We now know the value is a Some
var_dump($option->value);
```

If you suddenly provide your own version of None the code above will
break. This is probably more obvious when you look at the
enum-equivalent.

```
enum Option {
case None;
case Some($value);
}
```

To most people it's obvious that you can't add new cases to an
existing enum. It doesn't sound sensible to add logging to a data
class. That's something that belongs into a hook or service of some
kind.

People might also want to use sealed for behavioral classes, the use
case here is the same as final. Final is not here to make your life
harder. It's here to make the lives of the library maintainers easier.
If they have to reason about every way a method could be overridden,
every change in the library would become more risky, require more
thought and more frequent major version updates. This means more work
and less features for you, too.

Ilija

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread David Gebler
Yes I agree Chris, this is the same kind of argument I am making.

> Note that the *exact* same argument could be made for typing parameters.
I can document via a docblock that I expect a given parameter to be a
string, or a Request object, or whatever.  "There is little to no benefit
in expressing that through a new language construct rather than through
existing constructs and design patterns."

Yes and no. There is a critical difference between type checking and sealed
- type checking can actually prevent and catch bugs in the form of
objective logical errors (e.g. $total = getSum(1, 2, "not a number"))
before they occur, whereas sealed can only prevent things you did not
intend or foresee, without knowing anything about how I am using some code;
there is no bug or logical error which the use of sealed will prevent *in
and of itself*.

> Except there very much is a benefit, for making the intent of code
clearer and for allowing the engine to syntactically make certain invalid
states impossible.

This is not runtime benefit, it is runtime overhead. PHP cannot generate a
better opcode sequence for knowing a class is sealed. In terms of
implementation, the only thing it can do is scream "Hey! The author of this
class didn't intend for you to use it this way!" - your IDE can do that
from an attribute.

And although I would say the claim no one will ever have a legitimate &
good reason to extend some class and be able to do so in a way which does
not violate whatever protections against invalid state you had in mind is a
very bold prediction which is rarely borne out by reality - my objection
here is not about people marking classes as sealed, it's that we don't need
a new language construct and keyword to achieve the only benefit it
delivers (declaration of intent to users and IDE). If PHP reasoned about
classes in the same way compiled, statically typed languages do and
therefore derived some tangible compile-time benefit from a sealed
construct, I would be in favour of it.


On Mon, 26 Apr 2021, 08:54 Christian Schneider, 
wrote:

> Am 25.04.2021 um 05:47 schrieb Larry Garfield :
> > In practice, I think all of the use cases for sealed classes are
> ADT-esque.  As I noted before, combining sealed classes with Nikita's
> new-in-expressions RFC would allow for this (also using my short-functions
> RFC for this example, although that's a nice-to-have):
> >
> > sealed class Maybe permits Some, None {
>
> ...
>
> > }
> >
> > final class None extends Maybe {}
>
>
>
> This is exactly the thing I'm worried about.
>
> Say I want to add something like logging to the None type.
> Now your sealed and final classes prevent me from defining MyNone
> extending None even though it would be 100% compatible with None. Just
> because *you* deemed that useless or wrong.
>
> I've encountered situations like this and came to the conclusion that
> while this makes sense for languages like Haskell - where the whole idea is
> to be able to reason about a complex type system - it is an anti-pattern
> for other languages like PHP.
>
> Referring to another post, not yours: People, please don't use Java as a
> reason to add something to PHP, Java is the king of anti-patterns ;-)
>
> - Chris
>
>


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Christian Schneider
Am 25.04.2021 um 05:47 schrieb Larry Garfield :
> In practice, I think all of the use cases for sealed classes are ADT-esque.  
> As I noted before, combining sealed classes with Nikita's new-in-expressions 
> RFC would allow for this (also using my short-functions RFC for this example, 
> although that's a nice-to-have):
> 
> sealed class Maybe permits Some, None {

...

> }
> 
> final class None extends Maybe {}



This is exactly the thing I'm worried about.

Say I want to add something like logging to the None type.
Now your sealed and final classes prevent me from defining MyNone extending 
None even though it would be 100% compatible with None. Just because *you* 
deemed that useless or wrong.

I've encountered situations like this and came to the conclusion that while 
this makes sense for languages like Haskell - where the whole idea is to be 
able to reason about a complex type system - it is an anti-pattern for other 
languages like PHP.

Referring to another post, not yours: People, please don't use Java as a reason 
to add something to PHP, Java is the king of anti-patterns ;-)

- Chris



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Olle Härstedt
2021-04-26 9:37 GMT+02:00, Pierre :
> Le 26/04/2021 à 09:35, Olle Härstedt a écrit :
>> 2021-04-26 9:22 GMT+02:00, Pierre :
>>> Le 25/04/2021 à 21:22, Larry Garfield a écrit :
 Stitching together 2 replies to minimize thread noise...

 On Sun, Apr 25, 2021, at 11:58 AM, Michał Marcin Brzuchalski wrote:

> Speaking of Attributes I prefer not to use an Attribute for any
> particular
> language feature which expects input arguments to be a valid class or
> interface name for two reasons: first because there is no effective
> way
> to
> restrict input string to be a valid class or interface name and second
> that
> it'd require passing strings which means in most cases passing class
> or
> interface name with magic ::class constant read.
>
> Cheers,
> Michał Marcin Brzuchalski
 That's actually a pretty solid argument against attributes here,
 honestly.
   Consider me convinced, and now in favor of "final class Foo permits
 Bar,
 Baz". :-)

>>> Yes, even though I was the first mail suggesting it in the beginning,
>>> this is a solid argument which actually do change my mind.
>>>
>>> In the end, I like the `class Foo permis Bar, Baz` syntax, with a single
>>> keyword added.
>>>
>>> --
>>>
>>> Pierre
>>>
>>> --
>>> PHP Internals - PHP Runtime Development Mailing List
>>> To unsubscribe, visit: https://www.php.net/unsub.php
>>>
>>>
>> Is there actually a bug that this functionality can/could prevent? I
>> get that Maybe and Result types should be closed, but what are the
>> risk of software defects if someone abuses that fact (locally)?
>
> I don't know if you replied to the right mail, I should have specified I
> was talking about using an attribute versus adding a new keyword to the
> language.

Sorry, I was replying to the thread in general, not your reply
specifically. ^^ Maybe I should have replied to the top mail instead,
sorry.

Olle

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Pierre

Le 26/04/2021 à 09:35, Olle Härstedt a écrit :

2021-04-26 9:22 GMT+02:00, Pierre :

Le 25/04/2021 à 21:22, Larry Garfield a écrit :

Stitching together 2 replies to minimize thread noise...

On Sun, Apr 25, 2021, at 11:58 AM, Michał Marcin Brzuchalski wrote:


Speaking of Attributes I prefer not to use an Attribute for any
particular
language feature which expects input arguments to be a valid class or
interface name for two reasons: first because there is no effective way
to
restrict input string to be a valid class or interface name and second
that
it'd require passing strings which means in most cases passing class or
interface name with magic ::class constant read.

Cheers,
Michał Marcin Brzuchalski

That's actually a pretty solid argument against attributes here, honestly.
  Consider me convinced, and now in favor of "final class Foo permits Bar,
Baz". :-)


Yes, even though I was the first mail suggesting it in the beginning,
this is a solid argument which actually do change my mind.

In the end, I like the `class Foo permis Bar, Baz` syntax, with a single
keyword added.

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Is there actually a bug that this functionality can/could prevent? I
get that Maybe and Result types should be closed, but what are the
risk of software defects if someone abuses that fact (locally)?


I don't know if you replied to the right mail, I should have specified I 
was talking about using an attribute versus adding a new keyword to the 
language.


--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Olle Härstedt
2021-04-26 9:22 GMT+02:00, Pierre :
> Le 25/04/2021 à 21:22, Larry Garfield a écrit :
>> Stitching together 2 replies to minimize thread noise...
>>
>> On Sun, Apr 25, 2021, at 11:58 AM, Michał Marcin Brzuchalski wrote:
>>
>>> Speaking of Attributes I prefer not to use an Attribute for any
>>> particular
>>> language feature which expects input arguments to be a valid class or
>>> interface name for two reasons: first because there is no effective way
>>> to
>>> restrict input string to be a valid class or interface name and second
>>> that
>>> it'd require passing strings which means in most cases passing class or
>>> interface name with magic ::class constant read.
>>>
>>> Cheers,
>>> Michał Marcin Brzuchalski
>> That's actually a pretty solid argument against attributes here, honestly.
>>  Consider me convinced, and now in favor of "final class Foo permits Bar,
>> Baz". :-)
>>
> Yes, even though I was the first mail suggesting it in the beginning,
> this is a solid argument which actually do change my mind.
>
> In the end, I like the `class Foo permis Bar, Baz` syntax, with a single
> keyword added.
>
> --
>
> Pierre
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

Is there actually a bug that this functionality can/could prevent? I
get that Maybe and Result types should be closed, but what are the
risk of software defects if someone abuses that fact (locally)?

Olle

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-26 Thread Pierre

Le 25/04/2021 à 21:22, Larry Garfield a écrit :

Stitching together 2 replies to minimize thread noise...

On Sun, Apr 25, 2021, at 11:58 AM, Michał Marcin Brzuchalski wrote:


Speaking of Attributes I prefer not to use an Attribute for any particular
language feature which expects input arguments to be a valid class or
interface name for two reasons: first because there is no effective way to
restrict input string to be a valid class or interface name and second that
it'd require passing strings which means in most cases passing class or
interface name with magic ::class constant read.

Cheers,
Michał Marcin Brzuchalski

That's actually a pretty solid argument against attributes here, honestly.  Consider me 
convinced, and now in favor of "final class Foo permits Bar, Baz". :-)

Yes, even though I was the first mail suggesting it in the beginning, 
this is a solid argument which actually do change my mind.


In the end, I like the `class Foo permis Bar, Baz` syntax, with a single 
keyword added.


--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Mike Schinkel
I did not expect nor intend to go down the rabbit hole regarding this topic, so 
this will likely be my last reply on this thread.

> On Apr 25, 2021, at 4:51 PM, David Gebler  wrote:
> 
> On Sun, Apr 25, 2021 at 8:52 PM Mike Schinkel  wrote:
> 
>>> On Apr 25, 2021, at 1:52 PM, David Gebler  wrote:
>>> 
>>> Still, all these problems are solved to the same degree if you add a
>>> #[Sealed] attribute to a class which has no functional impact. You have
>>> sufficiently indicated to any user that extending this class is not a
>>> designed feature and may cause backwards-incompatible breaks with future
>>> releases - in a way that both a programmer and IDE can reason about,
>> which
>>> in PHP's context is what matters. Attributes arguably even have a greater
>>> qualitative advantage that they can be applied right down as far as
>>> individual method parameters.
>> 
>> In my experience, if a developer needs access to a feature that is easily
>> available via the use of a method that is merely documented as internal-use
>> only, the developer will use it rather anyway than spend a lot more time
>> trying to work around what that method makes easily available.  Especially
>> if that documented internal-use only is about not subclassing.
>> 
>> And if many other developers do that, the original developer will still
>> have the same problem as if they didn't document it as internal-use only.
>> 
>> But I do acknowledge your experience might be different.  FWIW.
>> 
> 
> You're answering a different point to the one I'm making, which is that in
> contrast to a language like Java, where the compiler gets a benefit out of
> reasoning about virtual vs non-virtual methods, the use of sealed as a
> language construct in an interpreted language like PHP can do nothing which
> isn't already achieved by annotation - the expression of intent.

Assuming the annotation is only advisory and the keyword is actionable then of 
course PHP can do something not already achieved by annotation; it can throw an 
error when it comes across a class that attempts to extend a sealed class that 
has not named it as an exception.  

> 
>>> In Java the idea of final and sealed classes makes more sense, since we
>>> actually to some extent need the compiler to be able to reason about
>> these
>>> types and can gain optimization and code generation benefits from its
>> being
>>> able to do so. PHP's concept of typing and implementation of type
>> checking
>>> as an interpreted language is completely different.
>>> 
>>> I wonder, if final and sealed as language constructs really offer the
>>> guarantees about intent and safety their advocates say they do, why are
>>> they not the default? Why can no one point me to a language where I have
>> to
>>> write something like
>>> 
>>> extendable class Foo permits all {  }
>>> 
>>> (and there are people who would be in favour of making inheritability
>> this
>>> explicit, but I'm not one of them)
>> 
>> Well, I can't point you to a language that works that way because I don't
>> know more than a handful of languages in depth — although there may be one
>> — but I can point you to a language that does not even allow you to
>> subclass: Go.
>> 
>> The Go designers wanted to get away from the fragile base class problem so
>> they provided embedding instead:
>> 
>> 
>> https://medium.com/@simplyianm/why-gos-structs-are-superior-to-class-based-inheritance-b661ba897c67
>> 
>> I program more in Go now than in PHP, and I can confirm that its approach
>> works brilliantly. Better IMO than what PHP currently offers in that
>> respect.
>> 
> 
> Again, this doesn't seem relevant to the discussion in respect of PHP or
> the RFC we're talking about. I don't have a Go background but I'm learning
> it at the moment and I like it a lot. Nonetheless it's neither comparable
> to PHP nor object oriented in a conventional sense so any direct comparison
> here is probably not too useful.

If you are going to equivocate and add more limiting criteria to your claim 
post hoc then of course the example I provided won't be too useful.


>>> It's one thing as an author of code to say "I only intended and support
>>> this finite set of use-cases", it's quite another to say "and you should
>> be
>>> impeded from proceeding with any legitimate use-case I didn't imagine or
>>> foresee"
>> 
>> I do respect that as a user of other developer's code you might view it
>> that way.
>> 
>> But then I also can respect the library or framework developer who chooses
>> to make their own job less difficult by (wanting to) mark a class to be
>> sealed.
>> 
>> You claim "it's quite another thing to say" but I don't think a developer
>> of library or framework code should be required to offer features to their
>> users they do not want to offer.  It is the developer's prerogative; if
>> they want to be able to mark their classes as sealed they should be
>> empowered to do so. IMHO, anyway.
>> 
> 
> My argument is not that there aren't 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Larry Garfield
On Sun, Apr 25, 2021, at 3:51 PM, David Gebler wrote:

> My argument is not that there aren't legitimate cases where you want to
> indicate a class or interface as sealed, nor that developers should not be
> empowered to make this indication. 

Right here is the core point.  This is a subjective statement, and one with 
which I (and apparently many here) disagree.

Note that the *exact* same argument could be made for typing parameters.  I can 
document via a docblock that I expect a given parameter to be a string, or a 
Request object, or whatever.  "There is little to no benefit in expressing that 
through a new language construct rather than through existing constructs and 
design patterns."

Except there very much is a benefit, for making the intent of code clearer and 
for allowing the engine to syntactically make certain invalid states 
impossible.  Adding more typing power to PHP has been a phenomenal win over the 
past 15 years precisely because it converts certain bugs and error conditions 
into fatal errors with no additional work required on the part of the 
developer.  That is a *good thing*.

ADTs, sealed classes, enum, and other functionality in that space is a 
continuation of the same process: Allow developers to use the language syntax 
to make invalid states impossible to describe, and thus bugs from invalid state 
go away.

Documentation, in whatever form, simply can't do that.

It has nothing to do with "inheritance is dangerous."  It has to do with 
accurately and completely describing the problem space.

Also, sure, you can fork any library and hack out the parts you don't like.  
That is true for sealed classes, for enums, for property types, for the entire 
language.  It's also completely 100% irrelevant, precisely because you're 
modifying upstream code, so all bets are off anyway.  

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Saif Eddin Gmati
 On Sun, 25 Apr 2021 22:56:26 +0100 Chase Peeler  
wrote 

 > On Sun, Apr 25, 2021 at 11:36 AM Mike Schinkel  wrote: 
 >  
 > > 
 > > 
 > > > On Apr 24, 2021, at 7:39 PM, David Gebler  wrote: 
 > > > 
 > > > I don't love this idea, I'm not very fond of the final keyword, either; 
 > > 
 > > I'll start by saying the final keyword caused me a tremendous amount of 
 > > heartache because it was used on a class in a framework that I badly, 
 > > badly 
 > > needed to extend. 
 > > 
 > > But even so, I recognize why they used it, and I still don't have a great 
 > > argument for how they could address the reasons they used it some other 
 > > way. 
 > > 
 > > > I've always believed annotations (or attributes in PHP these days) are a 
 > > > better of way of indicating you, as an author of a class, did not write 
 > > it 
 > > > with inheritability in mind or intended than restricting language 
 > > features 
 > > > through syntactic constructs. 
 > > > 
 > > > The RFC says "when you have a class in your code base that shares some 
 > > > implementation detail between 2 or more other objects, your only 
 > > protection 
 > > > against others making use of this class is to add `@internal` 
 > > > annotation, 
 > > > which doesn't offer any runtime guarantee that no one is extending this 
 > > > object", to which I ask - why do you need this guarantee? What does it 
 > > > qualitatively add? If I make a judgement that I want to extend your 
 > > > class 
 > > > or implement your interface, I can just delete the sealed keyword from 
 > > your 
 > > > code and carry on. So it doesn't actually offer any guarantee at all 
 > > > that 
 > > > I'm not extending the type. 
 > > 
 > > Actually, it does offer such a guarantee.  It guarantees if you are using 
 > > a non-forked version of the original developer's (OD's) library or 
 > > framework then that class won't be extended. When someone pulls the 
 > > original non-forked version from its source repository — such as when 
 > > using 
 > > Composer — then that code will be (effectively) guaranteed not to be 
 > > extended. 
 > > 
 > > OTOH, if you do delete the sealed (or final) keyword you have then forked 
 > > the code, in a defacto manner if not a literal one. If you use a forked 
 > > version of the code, you now own the maintenance of that code and any bugs 
 > > that are generated by your forked changes in using code. The original 
 > > developer has no moral, ethical or even contractual obligation to care 
 > > about the breakage you cause. 
 > > 
 >  
 > I'd argue that if the original developer made clear that you shouldn't 
 > extend a class, then they still have no moral, ethical, or even contractual 
 > obligation to care about the fact you've used the object in a way they were 
 > clear was not supported. 
 >  
 > I'm with David on this one. I can understand the need to enforce a 
 > final/sealed concept for core functionality implemented in C which might do 
 > some funny things under the hood. I don't think that should be extended to 
 > userland. If you want to warn someone, that's fine. But don't totally 
 > prohibit them. 
 >  
 > Given the ability for composer to pull from forked repos and the easy of 
 > keeping a forked repo in sync with it's upstream version, creating a fork 
 > just to remove a sealed/final designation isn't that difficult to do. 
 >  
 >  
 > > 
 > > Hypothetical example:  You fork the code, remove sealed/final, then 
 > > subclass the code and add a method, let's call it ToString(). And you 
 > > write 
 > > your application to use ToString(). Now the OD releases a new minor 
 > > version 
 > > and they also add a ToString() method. Applications using your fork 
 > > probably cannot use the new version of the OD's library because when the 
 > > library calls ToString() your version is called. So you have to update 
 > > your 
 > > application to use the new version of the library and once again remove 
 > > sealed/final. 
 > > 
 > > AND, if your code is instead another add-on library, now users of your 
 > > add-on library will also have to fix their code too.  Which could 
 > > potentially be a large number of users if your add-on is successful. 
 > > 
 > > So not using final or sealed can result in some really hairy and possibly 
 > > impossible to fully resolve backward compatibility concerns for developers 
 > > who publish libraries and/or frameworks. 
 > > 
 > > > The best it can achieve is to indicate your 
 > > > intentions, which I believe can be adequately done today through an 
 > > > attribute, no addition to the language needed. 
 > > 
 > > Still, I concur with your concerns.  Developers too often implement final 
 > > classes in libraries and frameworks without fully addressing all the 
 > > use-cases and/or adding enough extensibility points because it makes their 
 > > lives easier.  Because of that final — and sealed, if added — can make the 
 > > life of an application developer a living hell. 
 > > 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Chase Peeler
On Sun, Apr 25, 2021 at 11:36 AM Mike Schinkel  wrote:

>
>
> > On Apr 24, 2021, at 7:39 PM, David Gebler  wrote:
> >
> > I don't love this idea, I'm not very fond of the final keyword, either;
>
> I'll start by saying the final keyword caused me a tremendous amount of
> heartache because it was used on a class in a framework that I badly, badly
> needed to extend.
>
> But even so, I recognize why they used it, and I still don't have a great
> argument for how they could address the reasons they used it some other way.
>
> > I've always believed annotations (or attributes in PHP these days) are a
> > better of way of indicating you, as an author of a class, did not write
> it
> > with inheritability in mind or intended than restricting language
> features
> > through syntactic constructs.
> >
> > The RFC says "when you have a class in your code base that shares some
> > implementation detail between 2 or more other objects, your only
> protection
> > against others making use of this class is to add `@internal` annotation,
> > which doesn't offer any runtime guarantee that no one is extending this
> > object", to which I ask - why do you need this guarantee? What does it
> > qualitatively add? If I make a judgement that I want to extend your class
> > or implement your interface, I can just delete the sealed keyword from
> your
> > code and carry on. So it doesn't actually offer any guarantee at all that
> > I'm not extending the type.
>
> Actually, it does offer such a guarantee.  It guarantees if you are using
> a non-forked version of the original developer's (OD's) library or
> framework then that class won't be extended. When someone pulls the
> original non-forked version from its source repository — such as when using
> Composer — then that code will be (effectively) guaranteed not to be
> extended.
>
> OTOH, if you do delete the sealed (or final) keyword you have then forked
> the code, in a defacto manner if not a literal one. If you use a forked
> version of the code, you now own the maintenance of that code and any bugs
> that are generated by your forked changes in using code. The original
> developer has no moral, ethical or even contractual obligation to care
> about the breakage you cause.
>

I'd argue that if the original developer made clear that you shouldn't
extend a class, then they still have no moral, ethical, or even contractual
obligation to care about the fact you've used the object in a way they were
clear was not supported.

I'm with David on this one. I can understand the need to enforce a
final/sealed concept for core functionality implemented in C which might do
some funny things under the hood. I don't think that should be extended to
userland. If you want to warn someone, that's fine. But don't totally
prohibit them.

Given the ability for composer to pull from forked repos and the easy of
keeping a forked repo in sync with it's upstream version, creating a fork
just to remove a sealed/final designation isn't that difficult to do.


>
> Hypothetical example:  You fork the code, remove sealed/final, then
> subclass the code and add a method, let's call it ToString(). And you write
> your application to use ToString(). Now the OD releases a new minor version
> and they also add a ToString() method. Applications using your fork
> probably cannot use the new version of the OD's library because when the
> library calls ToString() your version is called. So you have to update your
> application to use the new version of the library and once again remove
> sealed/final.
>
> AND, if your code is instead another add-on library, now users of your
> add-on library will also have to fix their code too.  Which could
> potentially be a large number of users if your add-on is successful.
>
> So not using final or sealed can result in some really hairy and possibly
> impossible to fully resolve backward compatibility concerns for developers
> who publish libraries and/or frameworks.
>
> > The best it can achieve is to indicate your
> > intentions, which I believe can be adequately done today through an
> > attribute, no addition to the language needed.
>
> Still, I concur with your concerns.  Developers too often implement final
> classes in libraries and frameworks without fully addressing all the
> use-cases and/or adding enough extensibility points because it makes their
> lives easier.  Because of that final — and sealed, if added — can make the
> life of an application developer a living hell.
>
> So what's the answer?  I don't know that I have the ultimate answer, but I
> would be a lot more comfortable with adding features to PHP such as ones
> like sealed that restrict the "O" in S.O.L.I.D.[0] if PHP were to offer the
> following three (3) things, all of which can be found in Go, and I am sure
> other languages:
>
> 1. Class embedding[1] — Allows one class to embed another and immediately
> have access to all its properties and methods, and also to be able to
> extract an instance 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread David Gebler
On Sun, Apr 25, 2021 at 8:52 PM Mike Schinkel  wrote:

> > On Apr 25, 2021, at 1:52 PM, David Gebler  wrote:
> >
> > Still, all these problems are solved to the same degree if you add a
> > #[Sealed] attribute to a class which has no functional impact. You have
> > sufficiently indicated to any user that extending this class is not a
> > designed feature and may cause backwards-incompatible breaks with future
> > releases - in a way that both a programmer and IDE can reason about,
> which
> > in PHP's context is what matters. Attributes arguably even have a greater
> > qualitative advantage that they can be applied right down as far as
> > individual method parameters.
>
> In my experience, if a developer needs access to a feature that is easily
> available via the use of a method that is merely documented as internal-use
> only, the developer will use it rather anyway than spend a lot more time
> trying to work around what that method makes easily available.  Especially
> if that documented internal-use only is about not subclassing.
>
> And if many other developers do that, the original developer will still
> have the same problem as if they didn't document it as internal-use only.
>
> But I do acknowledge your experience might be different.  FWIW.
>

You're answering a different point to the one I'm making, which is that in
contrast to a language like Java, where the compiler gets a benefit out of
reasoning about virtual vs non-virtual methods, the use of sealed as a
language construct in an interpreted language like PHP can do nothing which
isn't already achieved by annotation - the expression of intent.


>
> > In Java the idea of final and sealed classes makes more sense, since we
> > actually to some extent need the compiler to be able to reason about
> these
> > types and can gain optimization and code generation benefits from its
> being
> > able to do so. PHP's concept of typing and implementation of type
> checking
> > as an interpreted language is completely different.
> >
> > I wonder, if final and sealed as language constructs really offer the
> > guarantees about intent and safety their advocates say they do, why are
> > they not the default? Why can no one point me to a language where I have
> to
> > write something like
> >
> > extendable class Foo permits all {  }
> >
> > (and there are people who would be in favour of making inheritability
> this
> > explicit, but I'm not one of them)
>
> Well, I can't point you to a language that works that way because I don't
> know more than a handful of languages in depth — although there may be one
> — but I can point you to a language that does not even allow you to
> subclass: Go.
>
> The Go designers wanted to get away from the fragile base class problem so
> they provided embedding instead:
>
>
> https://medium.com/@simplyianm/why-gos-structs-are-superior-to-class-based-inheritance-b661ba897c67
>
> I program more in Go now than in PHP, and I can confirm that its approach
> works brilliantly. Better IMO than what PHP currently offers in that
> respect.
>

Again, this doesn't seem relevant to the discussion in respect of PHP or
the RFC we're talking about. I don't have a Go background but I'm learning
it at the moment and I like it a lot. Nonetheless it's neither comparable
to PHP nor object oriented in a conventional sense so any direct comparison
here is probably not too useful.


>
> > It's one thing as an author of code to say "I only intended and support
> > this finite set of use-cases", it's quite another to say "and you should
> be
> > impeded from proceeding with any legitimate use-case I didn't imagine or
> > foresee"
>
> I do respect that as a user of other developer's code you might view it
> that way.
>
> But then I also can respect the library or framework developer who chooses
> to make their own job less difficult by (wanting to) mark a class to be
> sealed.
>
> You claim "it's quite another thing to say" but I don't think a developer
> of library or framework code should be required to offer features to their
> users they do not want to offer.  It is the developer's prerogative; if
> they want to be able to mark their classes as sealed they should be
> empowered to do so. IMHO, anyway.
>

My argument is not that there aren't legitimate cases where you want to
indicate a class or interface as sealed, nor that developers should not be
empowered to make this indication. It is that in PHP, as an interpreted
language, there is little to no benefit in expressing this through a new
language construct than through existing constructs and design patterns.


>
> > In practice, the only thing I've ever seen this achieve is to create
> > difficulties, while the claimed benefits can be adequately (and better)
> > achieved through existing patterns like annotations, interfaces and DI.
>
> I would argue that maybe the reason you have only seen it create
> difficulties is because of your own perspective and experiences that are,
> by 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Mike Schinkel
> On Apr 25, 2021, at 1:52 PM, David Gebler  wrote:
> 
> Still, all these problems are solved to the same degree if you add a
> #[Sealed] attribute to a class which has no functional impact. You have
> sufficiently indicated to any user that extending this class is not a
> designed feature and may cause backwards-incompatible breaks with future
> releases - in a way that both a programmer and IDE can reason about, which
> in PHP's context is what matters. Attributes arguably even have a greater
> qualitative advantage that they can be applied right down as far as
> individual method parameters.

In my experience, if a developer needs access to a feature that is easily 
available via the use of a method that is merely documented as internal-use 
only, the developer will use it rather anyway than spend a lot more time trying 
to work around what that method makes easily available.  Especially if that 
documented internal-use only is about not subclassing.

And if many other developers do that, the original developer will still have 
the same problem as if they didn't document it as internal-use only.

But I do acknowledge your experience might be different.  FWIW.

> In Java the idea of final and sealed classes makes more sense, since we
> actually to some extent need the compiler to be able to reason about these
> types and can gain optimization and code generation benefits from its being
> able to do so. PHP's concept of typing and implementation of type checking
> as an interpreted language is completely different.
> 
> I wonder, if final and sealed as language constructs really offer the
> guarantees about intent and safety their advocates say they do, why are
> they not the default? Why can no one point me to a language where I have to
> write something like
> 
> extendable class Foo permits all {  }
> 
> (and there are people who would be in favour of making inheritability this
> explicit, but I'm not one of them)

Well, I can't point you to a language that works that way because I don't know 
more than a handful of languages in depth — although there may be one — but I 
can point you to a language that does not even allow you to subclass: Go.  

The Go designers wanted to get away from the fragile base class problem so they 
provided embedding instead:

https://medium.com/@simplyianm/why-gos-structs-are-superior-to-class-based-inheritance-b661ba897c67
 
I program more in Go now than in PHP, and I can confirm that its approach works 
brilliantly. Better IMO than what PHP currently offers in that respect.

> It's one thing as an author of code to say "I only intended and support
> this finite set of use-cases", it's quite another to say "and you should be
> impeded from proceeding with any legitimate use-case I didn't imagine or
> foresee"

I do respect that as a user of other developer's code you might view it that 
way.  

But then I also can respect the library or framework developer who chooses to 
make their own job less difficult by (wanting to) mark a class to be sealed.

You claim "it's quite another thing to say" but I don't think a developer of 
library or framework code should be required to offer features to their users 
they do not want to offer.  It is the developer's prerogative; if they want to 
be able to mark their classes as sealed they should be empowered to do so. 
IMHO, anyway.

> In practice, the only thing I've ever seen this achieve is to create
> difficulties, while the claimed benefits can be adequately (and better)
> achieved through existing patterns like annotations, interfaces and DI.

I would argue that maybe the reason you have only seen it create difficulties 
is because of your own perspective and experiences that are, by definition, 
anecdotal and thus limited.

OTOH Fabien Potencier and/or Taylor Otwell might have a different experiences 
and thus a different perspective on what those benefits are (but I am 
admittedly just hypothesizing here.)

-Mike

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Larry Garfield
Stitching together 2 replies to minimize thread noise...

On Sun, Apr 25, 2021, at 11:58 AM, Michał Marcin Brzuchalski wrote:

> Speaking of Attributes I prefer not to use an Attribute for any particular
> language feature which expects input arguments to be a valid class or
> interface name for two reasons: first because there is no effective way to
> restrict input string to be a valid class or interface name and second that
> it'd require passing strings which means in most cases passing class or
> interface name with magic ::class constant read.
> 
> Cheers,
> Michał Marcin Brzuchalski

That's actually a pretty solid argument against attributes here, honestly.  
Consider me convinced, and now in favor of "final class Foo permits Bar, Baz". 
:-)


On Sun, Apr 25, 2021, at 12:52 PM, David Gebler wrote:
> Still, all these problems are solved to the same degree if you add a
> #[Sealed] attribute to a class which has no functional impact. You have
> sufficiently indicated to any user that extending this class is not a
> designed feature and may cause backwards-incompatible breaks with future
> releases - in a way that both a programmer and IDE can reason about, which
> in PHP's context is what matters. Attributes arguably even have a greater
> qualitative advantage that they can be applied right down as far as
> individual method parameters.
> 
> In Java the idea of final and sealed classes makes more sense, since we
> actually to some extent need the compiler to be able to reason about these
> types and can gain optimization and code generation benefits from its being
> able to do so. PHP's concept of typing and implementation of type checking
> as an interpreted language is completely different.
> 
> I wonder, if final and sealed as language constructs really offer the
> guarantees about intent and safety their advocates say they do, why are
> they not the default? Why can no one point me to a language where I have to
> write something like
> 
> extendable class Foo permits all {  }
> 
> (and there are people who would be in favour of making inheritability this
> explicit, but I'm not one of them)
> 
> It's one thing as an author of code to say "I only intended and support
> this finite set of use-cases", it's quite another to say "and you should be
> impeded from proceeding with any legitimate use-case I didn't imagine or
> foresee"
> 
> In practice, the only thing I've ever seen this achieve is to create
> difficulties, while the claimed benefits can be adequately (and better)
> achieved through existing patterns like annotations, interfaces and DI.

Part of the challenge here, i think, is that PHP, like most classic OOP 
languages, uses the same syntax for two different things.  One is for product 
types (an int combined with a string together in a single struct), the other is 
bound values in closures (aka, methods in service objects).  That's arguably by 
design in classic OOP, and arguably a design flow in classic OOP. :-)

I can think of no reason at all to make a service object's class sealed.  For 
those, yes, you shouldn't forbid custom extension, and frankly I usually 
discourage the use of private variables, too, for the same reason.

For product types that are part of the domain, however, there are definitely 
use cases where you want a defined finite list of possible variants.  The 
Distance and Maybe examples upthread, for instance.  That's not always the 
case, but there are definitely cases for them.

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread David Gebler
Still, all these problems are solved to the same degree if you add a
#[Sealed] attribute to a class which has no functional impact. You have
sufficiently indicated to any user that extending this class is not a
designed feature and may cause backwards-incompatible breaks with future
releases - in a way that both a programmer and IDE can reason about, which
in PHP's context is what matters. Attributes arguably even have a greater
qualitative advantage that they can be applied right down as far as
individual method parameters.

In Java the idea of final and sealed classes makes more sense, since we
actually to some extent need the compiler to be able to reason about these
types and can gain optimization and code generation benefits from its being
able to do so. PHP's concept of typing and implementation of type checking
as an interpreted language is completely different.

I wonder, if final and sealed as language constructs really offer the
guarantees about intent and safety their advocates say they do, why are
they not the default? Why can no one point me to a language where I have to
write something like

extendable class Foo permits all {  }

(and there are people who would be in favour of making inheritability this
explicit, but I'm not one of them)

It's one thing as an author of code to say "I only intended and support
this finite set of use-cases", it's quite another to say "and you should be
impeded from proceeding with any legitimate use-case I didn't imagine or
foresee"

In practice, the only thing I've ever seen this achieve is to create
difficulties, while the claimed benefits can be adequately (and better)
achieved through existing patterns like annotations, interfaces and DI.


On Sun, Apr 25, 2021 at 4:36 PM Mike Schinkel  wrote:

>
>
> On Apr 24, 2021, at 7:39 PM, David Gebler  wrote:
>
> I don't love this idea, I'm not very fond of the final keyword, either;
>
>
> I'll start by saying the final keyword caused me a tremendous amount of
> heartache because it was used on a class in a framework that I badly, badly
> needed to extend.
>
> But even so, I recognize why they used it, and I still don't have a great
> argument for how they could address the reasons they used it some other way.
>
> I've always believed annotations (or attributes in PHP these days) are a
> better of way of indicating you, as an author of a class, did not write it
> with inheritability in mind or intended than restricting language features
> through syntactic constructs.
>
> The RFC says "when you have a class in your code base that shares some
> implementation detail between 2 or more other objects, your only protection
> against others making use of this class is to add `@internal` annotation,
> which doesn't offer any runtime guarantee that no one is extending this
> object", to which I ask - why do you need this guarantee? What does it
> qualitatively add? If I make a judgement that I want to extend your class
> or implement your interface, I can just delete the sealed keyword from your
> code and carry on. So it doesn't actually offer any guarantee at all that
> I'm not extending the type.
>
>
> Actually, it does offer such a guarantee.  It guarantees if you are using
> a non-forked version of the original developer's (OD's) library or
> framework then that class won't be extended. When someone pulls the
> original non-forked version from its source repository — such as when using
> Composer — then that code will be (effectively) guaranteed not to be
> extended.
>
> OTOH, if you do delete the sealed (or final) keyword you have then forked
> the code, in a defacto manner if not a literal one. If you use a forked
> version of the code, you now own the maintenance of that code and any bugs
> that are generated by your forked changes in using code. The original
> developer has no moral, ethical or even contractual obligation to care
> about the breakage you cause.
>
> Hypothetical example:  You fork the code, remove sealed/final, then
> subclass the code and add a method, let's call it ToString(). And you write
> your application to use ToString(). Now the OD releases a new minor version
> and they also add a ToString() method. Applications using your fork
> probably cannot use the new version of the OD's library because when the
> library calls ToString() your version is called. So you have to update your
> application to use the new version of the library and once again remove
> sealed/final.
>
> AND, if your code is instead another add-on library, now users of your
> add-on library will also have to fix their code too.  Which could
> potentially be a large number of users if your add-on is successful.
>
> So not using final or sealed can result in some really hairy and possibly
> impossible to fully resolve backward compatibility concerns for developers
> who publish libraries and/or frameworks.
>
> The best it can achieve is to indicate your
> intentions, which I believe can be adequately done today through an

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Larry Garfield
On Sun, Apr 25, 2021, at 9:43 AM, Saif Eddin Gmati wrote:
>  On Sun, 25 Apr 2021 08:39:37 +0100 Olle Härstedt 
>  wrote 
> 
>  > > In practice, I think all of the use cases for sealed classes are 
> ADT-esque. 
>  > > As I noted before, combining sealed classes with Nikita's 
> new-in-expressions 
>  > > RFC would allow for this (also using my short-functions RFC for 
> this 
>  > > example, although that's a nice-to-have): 
>  > > 
>  > > sealed class Maybe permits Some, None { 
>  > > 
>  > >   public const None = new None(); 
>  > > 
>  > >   static public function Some($x) => new Some($x); 
>  > > 
>  > >   public function value() => throw new NotFoundException(); 
>  > > 
>  > >   public function bind(callable $c) => static::None; 
>  > > } 
>  > > 
>  > > final class None extends Maybe {} 
>  > > 
>  > > final class Some extends Maybe { 
>  > >   private $val; 
>  > >   private function __construct($x) { $this->val = $x; } 
>  > > 
>  > >   public function value() => $this->val; 
>  > > 
>  > >   public function bind(callable $c) => new static($c($this->val)); 
>  > > } 
>  >  
>  > Yes, the Maybe/Option type is a good example! Because you know there 
>  > will never be another extension. But it's worth noting that whenever 
>  > you do *not* know that, these concepts suffer, even in functional 
>  > programming, by the same issues as I mentioned before with regard to 
>  > maintainability - you can't easily extend it without touching old 
> code 
>  > (there are attempts to fix this by making algebraic datatypes 
>  > extensible, but it didn't get widely adopted AFAIK). Also see this 
>  > thread about the expression problem: 
>  > https://stackoverflow.com/a/871375/2138090 
>  >  
>  > Disregarding the limitations of maintainability, the real power of 
>  > algebraic datatypes is of course the pattern matching functionality 
>  > seen in OCaml and Haskell. I'm leaning towards tagged unions + 
> pattern 
>  > matching have more to offer PHP than sealed classes (and even more 
> so 
>  > when pattern matching can be extended with guard clauses and 
> catching 
>  > exceptions). The RFC author(s) might want to extend the RFC to 
> reflect 
>  > the relation to tagged unions, and how they overlap (or not)? 
>  >  
>  > Olle 

Pattern matching as it's currently being worked on would apply to arbitrary 
objects with visible properties, and enums are, in the engine, "just objects."  
So both a sealed class with public properties (or rather, properties visible in 
the scope) and an Enum with properties added (tagged unions/ADTs) would look 
the same to pattern matching.  Naturally that RFC has to get finished first, 
but assuming it is, it would apply either way.

(Discrete but complementary components FTW.)

> As mentioned in a previous email ( 
> https://news-web.php.net/php.internals/114134 ), there's many 
> differences between ADTs and Sealed classes,
> and in my opinion that's enough to have them both in the language as 
> personally i have use cases where ADTs won't work.

Many differences in terms of their implementation details, yes.  Ilija lays out 
a good list of those in that email.  However, they do address the same 
conceptual problem space.

Is there anything that ADTs or sealed classes would enable that the other one 
simply couldn't?  If we can get a list of those, that can help us determine 
which is the ideal route to pursue or if there really is value in adding both 
despite their heavy overlap.

(The list of links you had before lacks enough context for me to figure out 
what you're suggesting, sorry.  Please provide more precise comparisons of the 
two here.)

--

Also, another syntax suggestion:

final class Foo permits Bar, Baz {}

class Bar extends Foo {}

`final` already indicates that a class is inextensible.  Sealed classes are 
poking holes in that guard.  Essentially, final on its own is an extension 
cardinality of 0, sealed classes offer an exception list to that to give a 
precise cardinality list.

The main advantage here is that it introduces only a single new keyword, not 
multiple.  If `permits` were replaced with `for` (as the RFC already offers), 
it would be no new keywords.  Minimizing new keywords is generally a good idea 
anyway.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Olle Härstedt
2021-04-25 18:27 GMT+02:00, Larry Garfield :
> On Sun, Apr 25, 2021, at 2:04 AM, Olle Härstedt wrote:
>> > A total function is a function that is defined over the entire domain of
>> > its
>> > inputs.  For example, addition is a total function over integers,
>> > because
>> > for every possible pair of integers you pass to it there is a logical
>> > return
>> > value.  However, square root is not a total function over integers
>> > because
>> > there are some integers you pass it for which there is not
>> > representable
>> > return value.  (Negative numbers, unless you get into imaginary numbers
>> > which PHP doesn't support.)  In those cases, you have to throw an
>> > exception
>> > or return an error code or similar.
>>
>> Maybe nitpicking, but PHP-land shouldn't make up their own
>> definitions: "A total function is a function that is defined for all
>> possible values of its input. That is, it terminates and returns a
>> value."
>> https://softwareengineering.stackexchange.com/questions/334874/in-the-context-of-functional-programming-what-are-total-functions-and-partia
>>
>> Which means a total function is guaranteed to not have any errors,
>> like exceptions or division by zero. Compare with languages F* or Koka
>> which support this notation.
>
> That... is literally what I said.  There was no making up definitions.  I
> was using the actual mathematical definition.  PHP is quite capable of
> having total functions, they're a good thing, and we should try to encourage
> them where feasible.

What's the point of encouraging total functions if you can't express
the totality in the type system?

Olle

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Larry Garfield
On Sun, Apr 25, 2021, at 2:04 AM, Olle Härstedt wrote:
> > A total function is a function that is defined over the entire domain of its
> > inputs.  For example, addition is a total function over integers, because
> > for every possible pair of integers you pass to it there is a logical return
> > value.  However, square root is not a total function over integers because
> > there are some integers you pass it for which there is not representable
> > return value.  (Negative numbers, unless you get into imaginary numbers
> > which PHP doesn't support.)  In those cases, you have to throw an exception
> > or return an error code or similar.
> 
> Maybe nitpicking, but PHP-land shouldn't make up their own
> definitions: "A total function is a function that is defined for all
> possible values of its input. That is, it terminates and returns a
> value." 
> https://softwareengineering.stackexchange.com/questions/334874/in-the-context-of-functional-programming-what-are-total-functions-and-partia
> 
> Which means a total function is guaranteed to not have any errors,
> like exceptions or division by zero. Compare with languages F* or Koka
> which support this notation.

That... is literally what I said.  There was no making up definitions.  I was 
using the actual mathematical definition.  PHP is quite capable of having total 
functions, they're a good thing, and we should try to encourage them where 
feasible.

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Larry Garfield
On Sun, Apr 25, 2021, at 9:48 AM, Mike Schinkel wrote:

> > A total function is a function that is defined over the entire domain of 
> > its inputs.  For example, addition is a total function over integers, 
> > because for every possible pair of integers you pass to it there is a 
> > logical return value.  However, square root is not a total function over 
> > integers because there are some integers you pass it for which there is not 
> > representable return value.  (Negative numbers, unless you get into 
> > imaginary numbers which PHP doesn't support.)  In those cases, you have to 
> > throw an exception or return an error code or similar.
> > 
> > For a more typical PHP example, getUser(int $id) is not a total function, 
> > unless you have PHP_MAX_INT user objects defined in your database.  If you 
> > pass an int that does not correspond to a defined user, you now have to 
> > deal with "user not found" error handling.  getUser() is not a total 
> > function.  getUsers(array $criteria), however, arguably is, because it's 
> > logical and reasonable to map all not-found cases to an empty 
> > array/collection, which doesn't require any special error handling.

> Nothing I am about to write is meant to question the value of total 
> functions, but can you speak to the ramifications of a developer using 
> a library with a total function that returns miles or kilometers in 
> (say) version 2.0, along with the assumed guarantees of said function, 
> but then in version 3.0 the developer adds furlongs as a unit of 
> measure?
> 
> Yes going from 2.0 to 3.0 is a breaking change per semver, but it 
> doesn't feel like it had to be had the application developer not made 
> the total function assumption.
> 
> -Mike

It would be a breaking change, because you're changing the definition of the 
problem space.  Just as if you added a new option to an enum, or changed an 
Interface to have a method return iterable instead of array.  If you change the 
definition of the data model, that's a breaking change and all bets are off 
anyway.

Whether or not making it sealed in the first place was a good call is going to 
vary widely depending on the situation.  They're really not appropriate for 
service objects, where by design you could have an infinite number of possible 
PaymentGateway objects.  They're much more applicable for data objects that 
represent a finite number of business-relevant situations, where changing them 
means the problem space is changing *anyway* so changing code around the 
problem space is going to happen anyway.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Mike Schinkel


> On Apr 24, 2021, at 7:39 PM, David Gebler  wrote:
> 
> I don't love this idea, I'm not very fond of the final keyword, either;

I'll start by saying the final keyword caused me a tremendous amount of 
heartache because it was used on a class in a framework that I badly, badly 
needed to extend.

But even so, I recognize why they used it, and I still don't have a great 
argument for how they could address the reasons they used it some other way.

> I've always believed annotations (or attributes in PHP these days) are a
> better of way of indicating you, as an author of a class, did not write it
> with inheritability in mind or intended than restricting language features
> through syntactic constructs.
> 
> The RFC says "when you have a class in your code base that shares some
> implementation detail between 2 or more other objects, your only protection
> against others making use of this class is to add `@internal` annotation,
> which doesn't offer any runtime guarantee that no one is extending this
> object", to which I ask - why do you need this guarantee? What does it
> qualitatively add? If I make a judgement that I want to extend your class
> or implement your interface, I can just delete the sealed keyword from your
> code and carry on. So it doesn't actually offer any guarantee at all that
> I'm not extending the type.

Actually, it does offer such a guarantee.  It guarantees if you are using a 
non-forked version of the original developer's (OD's) library or framework then 
that class won't be extended. When someone pulls the original non-forked 
version from its source repository — such as when using Composer — then that 
code will be (effectively) guaranteed not to be extended.

OTOH, if you do delete the sealed (or final) keyword you have then forked the 
code, in a defacto manner if not a literal one. If you use a forked version of 
the code, you now own the maintenance of that code and any bugs that are 
generated by your forked changes in using code. The original developer has no 
moral, ethical or even contractual obligation to care about the breakage you 
cause.

Hypothetical example:  You fork the code, remove sealed/final, then subclass 
the code and add a method, let's call it ToString(). And you write your 
application to use ToString(). Now the OD releases a new minor version and they 
also add a ToString() method. Applications using your fork probably cannot use 
the new version of the OD's library because when the library calls ToString() 
your version is called. So you have to update your application to use the new 
version of the library and once again remove sealed/final.

AND, if your code is instead another add-on library, now users of your add-on 
library will also have to fix their code too.  Which could potentially be a 
large number of users if your add-on is successful.

So not using final or sealed can result in some really hairy and possibly 
impossible to fully resolve backward compatibility concerns for developers who 
publish libraries and/or frameworks.

> The best it can achieve is to indicate your
> intentions, which I believe can be adequately done today through an
> attribute, no addition to the language needed.

Still, I concur with your concerns.  Developers too often implement final 
classes in libraries and frameworks without fully addressing all the use-cases 
and/or adding enough extensibility points because it makes their lives easier.  
Because of that final — and sealed, if added — can make the life of an 
application developer a living hell.

So what's the answer?  I don't know that I have the ultimate answer, but I 
would be a lot more comfortable with adding features to PHP such as ones like 
sealed that restrict the "O" in S.O.L.I.D.[0] if PHP were to offer the 
following three (3) things, all of which can be found in Go, and I am sure 
other languages:

1. Class embedding[1] — Allows one class to embed another and immediately have 
access to all its properties and methods, and also to be able to extract an 
instance of that embedded class.  It is called "Type embedding" in Go.

2.Type definitions[2] — A typedef would allow developers to define constrained 
versions of existing types, such as `FiveStarRating` which could only contain 
1, 2, 3, 4 or 5, or types that identify a signature, for example as 
`ConvertToString` which could require a closure that implements 
`func(mixed):string`. In Go you can compose other types to create new types, 
but I'm not sure if those other type of types could apply to PHP, at least as 
it currently exists, and especially because it is not a compiled language.

3. Structural typing[3] — Basically interfaces that can be implemented 
implicitly rather than explicitly.  For example, if I wanted to implement a 
Stringable interface that requires a ToString():string method then structural 
typing would allow me to implement that interface simply by adding a ToString() 
method instead of requiring me to also add 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Saif Eddin Gmati
 > personally I'm okay with using an attribute, but using a keyword for type 
 > system related features seems like a better fit. 
 >  
 >  
 >  
 > I have added it to the alternative syntax list, which would have a separate 
 > vote. 
 >  
 >  
 >  
 > https://wiki.php.net/rfc/sealed_classes#syntax 
 >  
 >  
 >  
 >  
 >  
 >  
 >  
 >  
 >  On Sat, 24 Apr 2021 16:24:03 +0100 Matthew Brown 
 >  wrote  
 >  
 >  
 >  
 >  
 > > On Apr 24, 2021, at 10:43 AM, Levi Morrison via internals 
 > >  wrote: 
 > > 
 > > On Sat, Apr 24, 2021 at 8:04 AM Benjamin Eberlei 
 > >  wrote: 
 > >> 
 > >>> On Sat, Apr 24, 2021 at 2:56 PM Pierre  
 > >>> wrote: 
 > >>> 
 > >>> Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit : 
 >  Hello Internals, 
 >  
 >  I'm sending this email to open discussion about sealed classes, 
 >  interfaces, and traits feature for PHP 8.1. 
 >  
 >  I have create a Draft RFC here: 
 >  https://wiki.php.net/rfc/sealed_classes 
 >   
 >  
 >  A major concern for few people have been the syntax, in which it 
 >  introduces 2 new keywords into the languages, therefor, i have added a 
 >  section about alternative syntax which could be used to avoid this 
 >  problem. 
 >  
 >  Regards, 
 >  
 >  Saif. 
 > >>> 
 > >>> Hello, 
 > >>> 
 > >>> And why not using an attribute, such as in HackLang ? 
 > >>> 
 > >> 
 > >> +1 on this, I said the same on the "never/noreturn" RFC. There is a much 
 > >> less invasive way to add new keywords/flags to functions by using 
 > >> attributes. 
 > >> 
 > >> Imho this decouples new features from the language and reduces the "risk" 
 > >> of adding them to the language. That should increase the likeliness of it 
 > >> getting accepted in my opinion. 
 > > 
 > > I think an attribute may be appropriate here because sealed types act 
 > > like normal types, except we restrict who can extend them. 
 > > Additionally, we have to provide data about which types can extend the 
 > > sealed type, so it's not just a simple on/off type behavioral switch 
 > > (which I think is an antipattern for attributes based on my experience 
 > > in other languages that have them). 
 > > 
 > > This is different from a return type `never`. A function which never 
 > > returns cannot meaningfully have any return type at all -- using 
 > > `void` or some other type with an attribute would be a lie. 
 > > Additionally, there isn't any meta-data to associate with the `never`. 
 > > I hope this comment doesn't digress into a conversation about `never`; 
 > > that isn't my point. I'm trying to provide more justification about 
 > > when I think attributes are appropriate, because I think they may be 
 > > appropriate here and I think it's useful to show how `never` is 
 > > different. 
 > > 
 > > -- 
 > > PHP Internals - PHP Runtime Development Mailing List 
 > > To unsubscribe, visit: https://www.php.net/unsub.php 
 > > 
 >  
 > Yeah I second this — I think an attribute might be more appropriate here, 
 > and I obviously didn’t feel that way about the “never” RFC. 
 >  
 > One big benefit of a keyword over an equivalent attribute is that when you 
 > see `#[Sealed(...)]` you have to check use statements above to ensure it 
 > refers to the actual ‘Sealed’ attribute. 
 >  
 > What if PHP reserved double-underscore-prefixed attributes for engine use 
 > (and treated them as fully-qualified)? Hack does this currently, so you 
 > always know what a `<<__Sealed(Foo::class, Bar::class)>>` attribute will do, 
 > regardless of use statements. 
 >  
 > Best wishes, 
 >  
 > Matt 
 > -- 
 > PHP Internals - PHP Runtime Development Mailing List 
 > To unsubscribe, visit: https://www.php.net/unsub.php


Note: i have removed the choice for `#[Sealed(...)]` attribute syntax, while i 
don't mind it, i don't see a valid point for using attributes, other features ( 
e.g final classes ) use modifiers, and so should `sealed` as it is more 
comparable to `final` than other stuff people usually use attributes for ( e.g: 
#[Assert\Length(min: 2)], #[ORM\Entity], #[ApiResource] .. etc ).

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Mike Schinkel



> On Apr 24, 2021, at 11:47 PM, Larry Garfield  wrote:
> 
> On Sat, Apr 24, 2021, at 2:55 PM, Olle Härstedt wrote:
>> 2021-04-24 21:51 GMT+02:00, Marco Pivetta :
>>> On Sat, Apr 24, 2021, 21:44 Olle Härstedt  wrote:
>>> 
 2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
>> Doesn't this violate the principle: It should be possible to add new
>> features without touching old code?
> 
> This depends on which syntax is picked, both `for` and attribute syntax
 will
> be completely BC.
 
 I'm not talking about BC, but the maintainability of the new feature
 itself. For the shape example, you'd need to edit the original file
 for each new shape you add, which is detrimental for maintainability
 and scalability. So what's a good use-case?
 
>>> 
>>> The main use-case of sealed types is being able to declare total functions
>>> around them.
>> 
>> What is "total function" in your discourse? :) Can you find a more
>> concrete example? Preferably one that's relevant for web site/app
>> development. Shapes is a bit too generic, I think.
>> 
>> Olle
> 
> A total function is a function that is defined over the entire domain of its 
> inputs.  For example, addition is a total function over integers, because for 
> every possible pair of integers you pass to it there is a logical return 
> value.  However, square root is not a total function over integers because 
> there are some integers you pass it for which there is not representable 
> return value.  (Negative numbers, unless you get into imaginary numbers which 
> PHP doesn't support.)  In those cases, you have to throw an exception or 
> return an error code or similar.
> 
> For a more typical PHP example, getUser(int $id) is not a total function, 
> unless you have PHP_MAX_INT user objects defined in your database.  If you 
> pass an int that does not correspond to a defined user, you now have to deal 
> with "user not found" error handling.  getUser() is not a total function.  
> getUsers(array $criteria), however, arguably is, because it's logical and 
> reasonable to map all not-found cases to an empty array/collection, which 
> doesn't require any special error handling.
> 
> In practice, I think all of the use cases for sealed classes are ADT-esque.  
> As I noted before, combining sealed classes with Nikita's new-in-expressions 
> RFC would allow for this (also using my short-functions RFC for this example, 
> although that's a nice-to-have):
> 
> sealed class Maybe permits Some, None {
> 
>  public const None = new None();
> 
>  static public function Some($x) => new Some($x);
> 
>  public function value() => throw new NotFoundException();
> 
>  public function bind(callable $c) => static::None;
> }
> 
> final class None extends Maybe {}
> 
> final class Some extends Maybe {
>  private $val;
>  private function __construct($x) { $this->val = $x; }
> 
>  public function value() => $this->val;
> 
>  public function bind(callable $c) => new static($c($this->val));
> }
> 
> Now if you have an instance of Maybe, you can be absolutely guaranteed that 
> it's either an instance of Some or of None.  It's very similar to the 
> guarantee you get for enumerations, that you will have one of a fixed set of 
> dev-defined values and don't need to worry about any other case.  You handle 
> None, you handle Some, and now your function is a total function over its 
> Maybe parameter.
> 
> There are assorted other cases along those lines.
> 
> That gets you essentially the same functionality by a different route as what 
> the tagged unions RFC (https://wiki.php.net/rfc/tagged_unions) proposes:
> 
> enum Maybe {
>  case None {
>public function bind(callable $f) => $this;
>}
>  };
> 
>  case Some(private mixed $value) {
>public function bind(callable $f): Maybe => $f($this->value);
>  };
> 
>  public function value(): mixed => $this instanceof None 
>? throw new Exception()
>: $this->val;
> }
> 
> Or to use another example from the tagged unions RFC:
> 
> enum Distance {
>case Kilometers(public int $km);
>case Miles(public int $miles);
> }
> 
> vs:
> 
> sealed interface Distance permits Kilometers, Miles { ... }
> 
> class Kilometers implements Distance {
>  public function __construct(public int $km) {}
> }
> 
> class Miles implements Distance {
>  public function __construct(public int $miles) {}
> }
> 
> In either case, a function can now operate on distance and know that it's 
> dealing with a value in miles OR in kilometers, but it doesn't have to worry 
> about yards, furlongs, or light-years.  Combined with a pattern-matching 
> operator (which Ilija is working on here: 
> https://wiki.php.net/rfc/pattern-matching), it would make it possible to 
> combine ADTs/sealed classes with a match() statement and know that you've 
> covered every possible situation with a trivial amount of code.
> 
> Enums, Sealed classes, and tagged unions all play in the same logical space, 
> of allowing the 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Saif Eddin Gmati
 On Sun, 25 Apr 2021 08:39:37 +0100 Olle Härstedt  
wrote 

 > > In practice, I think all of the use cases for sealed classes are 
 > > ADT-esque. 
 > > As I noted before, combining sealed classes with Nikita's 
 > > new-in-expressions 
 > > RFC would allow for this (also using my short-functions RFC for this 
 > > example, although that's a nice-to-have): 
 > > 
 > > sealed class Maybe permits Some, None { 
 > > 
 > >   public const None = new None(); 
 > > 
 > >   static public function Some($x) => new Some($x); 
 > > 
 > >   public function value() => throw new NotFoundException(); 
 > > 
 > >   public function bind(callable $c) => static::None; 
 > > } 
 > > 
 > > final class None extends Maybe {} 
 > > 
 > > final class Some extends Maybe { 
 > >   private $val; 
 > >   private function __construct($x) { $this->val = $x; } 
 > > 
 > >   public function value() => $this->val; 
 > > 
 > >   public function bind(callable $c) => new static($c($this->val)); 
 > > } 
 >  
 > Yes, the Maybe/Option type is a good example! Because you know there 
 > will never be another extension. But it's worth noting that whenever 
 > you do *not* know that, these concepts suffer, even in functional 
 > programming, by the same issues as I mentioned before with regard to 
 > maintainability - you can't easily extend it without touching old code 
 > (there are attempts to fix this by making algebraic datatypes 
 > extensible, but it didn't get widely adopted AFAIK). Also see this 
 > thread about the expression problem: 
 > https://stackoverflow.com/a/871375/2138090 
 >  
 > Disregarding the limitations of maintainability, the real power of 
 > algebraic datatypes is of course the pattern matching functionality 
 > seen in OCaml and Haskell. I'm leaning towards tagged unions + pattern 
 > matching have more to offer PHP than sealed classes (and even more so 
 > when pattern matching can be extended with guard clauses and catching 
 > exceptions). The RFC author(s) might want to extend the RFC to reflect 
 > the relation to tagged unions, and how they overlap (or not)? 
 >  
 > Olle 
 >  
 > -- 
 > PHP Internals - PHP Runtime Development Mailing List 
 > To unsubscribe, visit: https://www.php.net/unsub.php 
 >  
 > 

As mentioned in a previous email ( 
https://news-web.php.net/php.internals/114134 ), there's many differences 
between ADTs and Sealed classes,
and in my opinion that's enough to have them both in the language as personally 
i have use cases where ADTs won't work.

examples:
- `sealed class UnionType permits ArrayKeyType, NumType` ( 
https://github.com/azjezz/psl/tree/1.7.x/src/Psl/Type/Internal )
- `sealed interface ExceptionInterface permits Exception` ( 
https://github.com/azjezz/psl/blob/1.7.x/src/Psl/Type/Exception ) - applies to 
all components in library
- `sealed class Exception permits AssertException, CoercionException` ( 
https://github.com/azjezz/psl/blob/1.7.x/src/Psl/Type/Exception )
- `sealed class ResourceHandle permits 
Psl\Filesystem\Internal\ResourceFileHandle` ( 
https://github.com/azjezz/psl/blob/asio/src/Psl/IO/Internal / 
https://github.com/azjezz/psl/tree/asio/src/Psl/Filesystem/Internal )

This is just a list of top of my head, the protection `sealed` offers is at the 
same level of `final`, expect it allow me to use inheritance internally without 
allowing the end users to do so.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Olle Härstedt
> In practice, I think all of the use cases for sealed classes are ADT-esque.
> As I noted before, combining sealed classes with Nikita's new-in-expressions
> RFC would allow for this (also using my short-functions RFC for this
> example, although that's a nice-to-have):
>
> sealed class Maybe permits Some, None {
>
>   public const None = new None();
>
>   static public function Some($x) => new Some($x);
>
>   public function value() => throw new NotFoundException();
>
>   public function bind(callable $c) => static::None;
> }
>
> final class None extends Maybe {}
>
> final class Some extends Maybe {
>   private $val;
>   private function __construct($x) { $this->val = $x; }
>
>   public function value() => $this->val;
>
>   public function bind(callable $c) => new static($c($this->val));
> }

Yes, the Maybe/Option type is a good example! Because you know there
will never be another extension. But it's worth noting that whenever
you do *not* know that, these concepts suffer, even in functional
programming, by the same issues as I mentioned before with regard to
maintainability - you can't easily extend it without touching old code
(there are attempts to fix this by making algebraic datatypes
extensible, but it didn't get widely adopted AFAIK). Also see this
thread about the expression problem:
https://stackoverflow.com/a/871375/2138090

Disregarding the limitations of maintainability, the real power of
algebraic datatypes is of course the pattern matching functionality
seen in OCaml and Haskell. I'm leaning towards tagged unions + pattern
matching have more to offer PHP than sealed classes (and even more so
when pattern matching can be extended with guard clauses and catching
exceptions). The RFC author(s) might want to extend the RFC to reflect
the relation to tagged unions, and how they overlap (or not)?

Olle

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Olle Härstedt
> For a more typical PHP example, getUser(int $id) is not a total function,
> unless you have PHP_MAX_INT user objects defined in your database.  If you
> pass an int that does not correspond to a defined user, you now have to deal
> with "user not found" error handling.  getUser() is not a total function.
> getUsers(array $criteria), however, arguably is, because it's logical and
> reasonable to map all not-found cases to an empty array/collection, which
> doesn't require any special error handling.

getUser() could return a nullable type. But totality assumes purity,
and I'm assuming you didn't hard-code all users inside the getUser()
function. :) As soon as you interact with the outside world, you can
have exception and errors, and thus you can't guarantee termination.
In any case, I think the concept of totality is pretty foreign to PHP,
and we can probably leave it behind (you'd have to make sure -
statically, in the type-system - there are no infinite recursion, no
infinite loops, ...).

Olle

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-25 Thread Olle Härstedt
> A total function is a function that is defined over the entire domain of its
> inputs.  For example, addition is a total function over integers, because
> for every possible pair of integers you pass to it there is a logical return
> value.  However, square root is not a total function over integers because
> there are some integers you pass it for which there is not representable
> return value.  (Negative numbers, unless you get into imaginary numbers
> which PHP doesn't support.)  In those cases, you have to throw an exception
> or return an error code or similar.

Maybe nitpicking, but PHP-land shouldn't make up their own
definitions: "A total function is a function that is defined for all
possible values of its input. That is, it terminates and returns a
value." 
https://softwareengineering.stackexchange.com/questions/334874/in-the-context-of-functional-programming-what-are-total-functions-and-partia

Which means a total function is guaranteed to not have any errors,
like exceptions or division by zero. Compare with languages F* or Koka
which support this notation.

I get your point tho. :)

Olle

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Larry Garfield
On Sat, Apr 24, 2021, at 2:55 PM, Olle Härstedt wrote:
> 2021-04-24 21:51 GMT+02:00, Marco Pivetta :
> > On Sat, Apr 24, 2021, 21:44 Olle Härstedt  wrote:
> >
> >> 2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
> >> >> Doesn't this violate the principle: It should be possible to add new
> >> >> features without touching old code?
> >> >
> >> > This depends on which syntax is picked, both `for` and attribute syntax
> >> will
> >> > be completely BC.
> >>
> >> I'm not talking about BC, but the maintainability of the new feature
> >> itself. For the shape example, you'd need to edit the original file
> >> for each new shape you add, which is detrimental for maintainability
> >> and scalability. So what's a good use-case?
> >>
> >
> > The main use-case of sealed types is being able to declare total functions
> > around them.
> 
> What is "total function" in your discourse? :) Can you find a more
> concrete example? Preferably one that's relevant for web site/app
> development. Shapes is a bit too generic, I think.
> 
> Olle

A total function is a function that is defined over the entire domain of its 
inputs.  For example, addition is a total function over integers, because for 
every possible pair of integers you pass to it there is a logical return value. 
 However, square root is not a total function over integers because there are 
some integers you pass it for which there is not representable return value.  
(Negative numbers, unless you get into imaginary numbers which PHP doesn't 
support.)  In those cases, you have to throw an exception or return an error 
code or similar.

For a more typical PHP example, getUser(int $id) is not a total function, 
unless you have PHP_MAX_INT user objects defined in your database.  If you pass 
an int that does not correspond to a defined user, you now have to deal with 
"user not found" error handling.  getUser() is not a total function.  
getUsers(array $criteria), however, arguably is, because it's logical and 
reasonable to map all not-found cases to an empty array/collection, which 
doesn't require any special error handling.

In practice, I think all of the use cases for sealed classes are ADT-esque.  As 
I noted before, combining sealed classes with Nikita's new-in-expressions RFC 
would allow for this (also using my short-functions RFC for this example, 
although that's a nice-to-have):

sealed class Maybe permits Some, None {

  public const None = new None();

  static public function Some($x) => new Some($x);

  public function value() => throw new NotFoundException();

  public function bind(callable $c) => static::None;
}

final class None extends Maybe {}

final class Some extends Maybe {
  private $val;
  private function __construct($x) { $this->val = $x; }

  public function value() => $this->val;

  public function bind(callable $c) => new static($c($this->val));
}

Now if you have an instance of Maybe, you can be absolutely guaranteed that 
it's either an instance of Some or of None.  It's very similar to the guarantee 
you get for enumerations, that you will have one of a fixed set of dev-defined 
values and don't need to worry about any other case.  You handle None, you 
handle Some, and now your function is a total function over its Maybe parameter.

There are assorted other cases along those lines.

That gets you essentially the same functionality by a different route as what 
the tagged unions RFC (https://wiki.php.net/rfc/tagged_unions) proposes:

enum Maybe {
  case None {
public function bind(callable $f) => $this;
}
  };
 
  case Some(private mixed $value) {
public function bind(callable $f): Maybe => $f($this->value);
  };
 
  public function value(): mixed => $this instanceof None 
? throw new Exception()
: $this->val;
}

Or to use another example from the tagged unions RFC:

enum Distance {
case Kilometers(public int $km);
case Miles(public int $miles);
}

vs:

sealed interface Distance permits Kilometers, Miles { ... }

class Kilometers implements Distance {
  public function __construct(public int $km) {}
}

class Miles implements Distance {
  public function __construct(public int $miles) {}
}

In either case, a function can now operate on distance and know that it's 
dealing with a value in miles OR in kilometers, but it doesn't have to worry 
about yards, furlongs, or light-years.  Combined with a pattern-matching 
operator (which Ilija is working on here: 
https://wiki.php.net/rfc/pattern-matching), it would make it possible to 
combine ADTs/sealed classes with a match() statement and know that you've 
covered every possible situation with a trivial amount of code.

Enums, Sealed classes, and tagged unions all play in the same logical space, of 
allowing the developer to more precisely define their problem space and data 
model in a way that "makes invalid states unrepresentable",,and thus eliminates 
a large amount of error handling resulting in code that is harder if not 
impossible to "get wrong."  

I 

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread David Gebler
I don't love this idea, I'm not very fond of the final keyword, either;
I've always believed annotations (or attributes in PHP these days) are a
better of way of indicating you, as an author of a class, did not write it
with inheritability in mind or intended than restricting language features
through syntactic constructs.

The RFC says "when you have a class in your code base that shares some
implementation detail between 2 or more other objects, your only protection
against others making use of this class is to add `@internal` annotation,
which doesn't offer any runtime guarantee that no one is extending this
object", to which I ask - why do you need this guarantee? What does it
qualitatively add? If I make a judgement that I want to extend your class
or implement your interface, I can just delete the sealed keyword from your
code and carry on. So it doesn't actually offer any guarantee at all that
I'm not extending the type. The best it can achieve is to indicate your
intentions, which I believe can be adequately done today through an
attribute, no addition to the language needed.

On Sat, Apr 24, 2021 at 9:01 PM Christian Schneider 
wrote:

> Am 24.04.2021 um 21:51 schrieb Marco Pivetta :
> > On Sat, Apr 24, 2021, 21:44 Olle Härstedt  > wrote:
> >
> >> 2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
>  Doesn't this violate the principle: It should be possible to add new
>  features without touching old code?
> >>>
> >>> This depends on which syntax is picked, both `for` and attribute syntax
> >> will
> >>> be completely BC.
> >>
> >> I'm not talking about BC, but the maintainability of the new feature
> >> itself. For the shape example, you'd need to edit the original file
> >> for each new shape you add, which is detrimental for maintainability
> >> and scalability. So what's a good use-case?
>
> I'm with Olle here: This sounds like an anti-pattern to me.
> The example could not be worse: Why should I not be allowed to add a
> hexagon shape?
>
> > The main use-case of sealed types is being able to declare total
> functions
> > around them.
>
> Could you elaborate on what's the real-world use-case for your main
> use-case?
> This sounds like another case of a feature based in (math) theory which
> leads to artificially locked down code.
>
> - Chris
>
>


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Christian Schneider
Am 24.04.2021 um 21:51 schrieb Marco Pivetta :
> On Sat, Apr 24, 2021, 21:44 Olle Härstedt  > wrote:
> 
>> 2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
 Doesn't this violate the principle: It should be possible to add new
 features without touching old code?
>>> 
>>> This depends on which syntax is picked, both `for` and attribute syntax
>> will
>>> be completely BC.
>> 
>> I'm not talking about BC, but the maintainability of the new feature
>> itself. For the shape example, you'd need to edit the original file
>> for each new shape you add, which is detrimental for maintainability
>> and scalability. So what's a good use-case?

I'm with Olle here: This sounds like an anti-pattern to me.
The example could not be worse: Why should I not be allowed to add a hexagon 
shape?

> The main use-case of sealed types is being able to declare total functions
> around them.

Could you elaborate on what's the real-world use-case for your main use-case?
This sounds like another case of a feature based in (math) theory which leads 
to artificially locked down code.

- Chris



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Olle Härstedt
2021-04-24 21:51 GMT+02:00, Marco Pivetta :
> On Sat, Apr 24, 2021, 21:44 Olle Härstedt  wrote:
>
>> 2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
>> >> Doesn't this violate the principle: It should be possible to add new
>> >> features without touching old code?
>> >
>> > This depends on which syntax is picked, both `for` and attribute syntax
>> will
>> > be completely BC.
>>
>> I'm not talking about BC, but the maintainability of the new feature
>> itself. For the shape example, you'd need to edit the original file
>> for each new shape you add, which is detrimental for maintainability
>> and scalability. So what's a good use-case?
>>
>
> The main use-case of sealed types is being able to declare total functions
> around them.

What is "total function" in your discourse? :) Can you find a more
concrete example? Preferably one that's relevant for web site/app
development. Shapes is a bit too generic, I think.

Olle

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Marco Pivetta
On Sat, Apr 24, 2021, 21:44 Olle Härstedt  wrote:

> 2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
> >> Doesn't this violate the principle: It should be possible to add new
> >> features without touching old code?
> >
> > This depends on which syntax is picked, both `for` and attribute syntax
> will
> > be completely BC.
>
> I'm not talking about BC, but the maintainability of the new feature
> itself. For the shape example, you'd need to edit the original file
> for each new shape you add, which is detrimental for maintainability
> and scalability. So what's a good use-case?
>

The main use-case of sealed types is being able to declare total functions
around them.


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Olle Härstedt
2021-04-24 17:59 GMT+02:00, Saif Eddin Gmati :
>> Doesn't this violate the principle: It should be possible to add new
>> features without touching old code?
>
> This depends on which syntax is picked, both `for` and attribute syntax will
> be completely BC.

I'm not talking about BC, but the maintainability of the new feature
itself. For the shape example, you'd need to edit the original file
for each new shape you add, which is detrimental for maintainability
and scalability. So what's a good use-case?

Olle

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Ilija Tovilo
Hi Saif

On Sat, Apr 24, 2021 at 1:35 PM Saif Eddin Gmati  wrote:
>
> Hello Internals,
>
> I'm sending this email to open discussion about sealed classes, interfaces, 
> and traits feature for PHP 8.1.
>
> I have create a Draft RFC here: https://wiki.php.net/rfc/sealed_classes
>
> A major concern for few people have been the syntax, in which it
> introduces 2 new keywords into the languages, therefor, i have added a
> section about alternative syntax which could be used to avoid this
> problem.

As mentioned off-list, I think there's some overlap with ADTs.
https://wiki.php.net/rfc/tagged_unions

There are two major motivations of sealed I can think of:

1. Usage in libraries for classes that can't be final because they're
extended by other internal classes. This prevents them from being
extended in user land and used in unintended ways, which reduces risks
of breaking changes.
2. For types have a fixed number of subtypes. This makes it possible
to handle a value by type and knowing that you've handled all possible
cases (exhaustiveness checks). Good examples are Option
(https://doc.rust-lang.org/std/option/enum.Option.html) or Result
(https://doc.rust-lang.org/std/result/enum.Result.html).

It could even be argued that 1 and 2 are the same. Enums/ADTs
essentially try to solve the same problem. This example is taken from
the RFC and rewritten as an enum:

```
enum Shape {
case Circle;
case Square;
case Rectangle;
}
```

Obviously this is the simplest case, but enums/ADTs allow adding
arbitrary data to each case and arbitrary behavior to the enum itself.
This approach differs from sealed in a few ways:

* Sealed allows (or requires in terms of autoloading) separating
subtypes into multiple files
* The subclasses of sealed classes are allowed to have diverging APIs,
while methods in enums are currently only allowed on the enum itself.
This could be changed but feedback from the enum RFC has shown this is
not desired by most people.
* Sealed could be used for existing classes without breaking the API too much.
* The syntax for enums is much more concise
* For cases with no data enums will create a singleton, while sealed
will require manually managing a singleton or creating an instance for
each value (e.g. new Option\None).

There's probably more, these are just off the top of my head. This
begs a few questions:

* Are these approaches different enough to justify both of them?
* If not, which is the preferable approach?

Ilija

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Saif Eddin Gmati
> Doesn't this violate the principle: It should be possible to add new features 
> without touching old code? 



This depends on which syntax is picked, both `for` and attribute syntax will be 
completely BC.



using `sealed`+`permits` or `permits` only will result in these keywords being 
reserved, so classes named `Sealed` or `Permits` will not work in PHP 8.1.

 

> Isn't namespace-internal access a better feature for the same purpose? That 
> is, only allows a class to be extended within the same namespace. 



No, this is a different feature, sealed classes can permit classes in a 
completely different namespace, and restrict inheritance to a per-defined list 
of classes.



If we would allow inheritance in the same namespace, it's extremely easy to get 
around it:



```

namespace Lib {

  abstract class MyProxy implements PrivateFooInterface {}

}



namespace App {

  class MyFooImplementation extends \Lib\MyProxy {

    // ...

  }

}

```



while it is possible to get around sealed, or even final keywords ( 
https://github.com/dg/bypass-finals/blob/master/src/BypassFinals.php ), 
bypassing private classes/interface is much easier, and doesn't require any 
hacks.











 On Sat, 24 Apr 2021 16:52:20 +0100 Olle Härstedt  
wrote 



2021-04-24 12:56 GMT, Pierre : 
> Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit : 
>> Hello Internals, 
>> 
>> I'm sending this email to open discussion about sealed classes, 
>> interfaces, and traits feature for PHP 8.1. 
>> 
>> I have create a Draft RFC here: 
>> https://wiki.php.net/rfc/sealed_classes 
>>  
>> 
>> A major concern for few people have been the syntax, in which it 
>> introduces 2 new keywords into the languages, therefor, i have added a 
>> section about alternative syntax which could be used to avoid this 
>> problem. 
>> 
>> Regards, 
>> 
>> Saif. 
 
1) Doesn't this violate the principle: It should be possible to add 
new features without touching old code? 
 
2) Isn't namespace-internal access a better feature for the same 
purpose? That is, only allows a class to be extended within the same 
namespace. 
 
Olle 
 
-- 
PHP Internals - PHP Runtime Development Mailing List 
To unsubscribe, visit: https://www.php.net/unsub.php

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Olle Härstedt
2021-04-24 12:56 GMT, Pierre :
> Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit :
>> Hello Internals,
>>
>> I'm sending this email to open discussion about sealed classes,
>> interfaces, and traits feature for PHP 8.1.
>>
>> I have create a Draft RFC here:
>> https://wiki.php.net/rfc/sealed_classes
>> 
>>
>> A major concern for few people have been the syntax, in which it
>> introduces 2 new keywords into the languages, therefor, i have added a
>> section about alternative syntax which could be used to avoid this
>> problem.
>>
>> Regards,
>>
>> Saif.

1) Doesn't this violate the principle: It should be possible to add
new features without touching old code?

2) Isn't namespace-internal access a better feature for the same
purpose? That is, only allows a class to be extended within the same
namespace.

Olle

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Saif Eddin Gmati
personally I'm okay with using an attribute, but using a keyword for type 
system related features seems like a better fit.



I have added it to the alternative syntax list, which would have a separate 
vote.



https://wiki.php.net/rfc/sealed_classes#syntax








 On Sat, 24 Apr 2021 16:24:03 +0100 Matthew Brown 
 wrote 




> On Apr 24, 2021, at 10:43 AM, Levi Morrison via internals 
>  wrote: 
> 
> On Sat, Apr 24, 2021 at 8:04 AM Benjamin Eberlei 
>  wrote: 
>> 
>>> On Sat, Apr 24, 2021 at 2:56 PM Pierre  
>>> wrote: 
>>> 
>>> Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit : 
 Hello Internals, 
 
 I'm sending this email to open discussion about sealed classes, 
 interfaces, and traits feature for PHP 8.1. 
 
 I have create a Draft RFC here: 
 https://wiki.php.net/rfc/sealed_classes 
  
 
 A major concern for few people have been the syntax, in which it 
 introduces 2 new keywords into the languages, therefor, i have added a 
 section about alternative syntax which could be used to avoid this 
 problem. 
 
 Regards, 
 
 Saif. 
>>> 
>>> Hello, 
>>> 
>>> And why not using an attribute, such as in HackLang ? 
>>> 
>> 
>> +1 on this, I said the same on the "never/noreturn" RFC. There is a much 
>> less invasive way to add new keywords/flags to functions by using 
>> attributes. 
>> 
>> Imho this decouples new features from the language and reduces the "risk" 
>> of adding them to the language. That should increase the likeliness of it 
>> getting accepted in my opinion. 
> 
> I think an attribute may be appropriate here because sealed types act 
> like normal types, except we restrict who can extend them. 
> Additionally, we have to provide data about which types can extend the 
> sealed type, so it's not just a simple on/off type behavioral switch 
> (which I think is an antipattern for attributes based on my experience 
> in other languages that have them). 
> 
> This is different from a return type `never`. A function which never 
> returns cannot meaningfully have any return type at all -- using 
> `void` or some other type with an attribute would be a lie. 
> Additionally, there isn't any meta-data to associate with the `never`. 
> I hope this comment doesn't digress into a conversation about `never`; 
> that isn't my point. I'm trying to provide more justification about 
> when I think attributes are appropriate, because I think they may be 
> appropriate here and I think it's useful to show how `never` is 
> different. 
> 
> -- 
> PHP Internals - PHP Runtime Development Mailing List 
> To unsubscribe, visit: https://www.php.net/unsub.php 
> 
 
Yeah I second this — I think an attribute might be more appropriate here, and I 
obviously didn’t feel that way about the “never” RFC. 
 
One big benefit of a keyword over an equivalent attribute is that when you see 
`#[Sealed(...)]` you have to check use statements above to ensure it refers to 
the actual ‘Sealed’ attribute. 
 
What if PHP reserved double-underscore-prefixed attributes for engine use (and 
treated them as fully-qualified)? Hack does this currently, so you always know 
what a `<<__Sealed(Foo::class, Bar::class)>>` attribute will do, regardless of 
use statements. 
 
Best wishes, 
 
Matt 
-- 
PHP Internals - PHP Runtime Development Mailing List 
To unsubscribe, visit: https://www.php.net/unsub.php

Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Matthew Brown


> On Apr 24, 2021, at 10:43 AM, Levi Morrison via internals 
>  wrote:
> 
> On Sat, Apr 24, 2021 at 8:04 AM Benjamin Eberlei  wrote:
>> 
>>> On Sat, Apr 24, 2021 at 2:56 PM Pierre  wrote:
>>> 
>>> Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit :
 Hello Internals,
 
 I'm sending this email to open discussion about sealed classes,
 interfaces, and traits feature for PHP 8.1.
 
 I have create a Draft RFC here:
 https://wiki.php.net/rfc/sealed_classes
 
 
 A major concern for few people have been the syntax, in which it
 introduces 2 new keywords into the languages, therefor, i have added a
 section about alternative syntax which could be used to avoid this
 problem.
 
 Regards,
 
 Saif.
>>> 
>>> Hello,
>>> 
>>> And why not using an attribute, such as in HackLang ?
>>> 
>> 
>> +1 on this, I said the same on the "never/noreturn" RFC. There is a much
>> less invasive way to add new keywords/flags to functions by using
>> attributes.
>> 
>> Imho this decouples new features from the language and reduces the "risk"
>> of adding them to the language. That should increase the likeliness of it
>> getting accepted in my opinion.
> 
> I think an attribute may be appropriate here because sealed types act
> like normal types, except we restrict who can extend them.
> Additionally, we have to provide data about which types can extend the
> sealed type, so it's not just a simple on/off type behavioral switch
> (which I think is an antipattern for attributes based on my experience
> in other languages that have them).
> 
> This is different from a return type `never`. A function which never
> returns cannot meaningfully have any return type at all -- using
> `void` or some other type with an attribute would be a lie.
> Additionally, there isn't any meta-data to associate with the `never`.
> I hope this comment doesn't digress into a conversation about `never`;
> that isn't my point. I'm trying to provide more justification about
> when I think attributes are appropriate, because I think they may be
> appropriate here and I think it's useful to show how `never` is
> different.
> 
> -- 
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
> 

Yeah I second this — I think an attribute might be more appropriate here, and I 
obviously didn’t feel that way about the “never” RFC.

One big benefit of a keyword over an equivalent attribute is that when you see 
`#[Sealed(...)]` you have to check use statements above to ensure it refers to 
the actual ‘Sealed’ attribute.

What if PHP reserved double-underscore-prefixed attributes for engine use (and 
treated them as fully-qualified)? Hack does this currently, so you always know 
what a `<<__Sealed(Foo::class, Bar::class)>>` attribute will do, regardless of 
use statements.

Best wishes,

Matt
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



[PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Saif Eddin Gmati
Hello Internals,

I'm sending this email to open discussion about sealed classes, interfaces, and 
traits feature for PHP 8.1.

I have create a Draft RFC here: https://wiki.php.net/rfc/sealed_classes

A major concern for few people have been the syntax, in which it introduces 2 
new keywords into the languages, therefor, i have added a section about 
alternative syntax which could be used to avoid this problem.

Regards,

Saif.

signature.asc
Description: OpenPGP digital signature


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Levi Morrison via internals
On Sat, Apr 24, 2021 at 8:04 AM Benjamin Eberlei  wrote:
>
> On Sat, Apr 24, 2021 at 2:56 PM Pierre  wrote:
>
> > Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit :
> > > Hello Internals,
> > >
> > > I'm sending this email to open discussion about sealed classes,
> > > interfaces, and traits feature for PHP 8.1.
> > >
> > > I have create a Draft RFC here:
> > > https://wiki.php.net/rfc/sealed_classes
> > > 
> > >
> > > A major concern for few people have been the syntax, in which it
> > > introduces 2 new keywords into the languages, therefor, i have added a
> > > section about alternative syntax which could be used to avoid this
> > > problem.
> > >
> > > Regards,
> > >
> > > Saif.
> >
> > Hello,
> >
> > And why not using an attribute, such as in HackLang ?
> >
>
> +1 on this, I said the same on the "never/noreturn" RFC. There is a much
> less invasive way to add new keywords/flags to functions by using
> attributes.
>
> Imho this decouples new features from the language and reduces the "risk"
> of adding them to the language. That should increase the likeliness of it
> getting accepted in my opinion.

I think an attribute may be appropriate here because sealed types act
like normal types, except we restrict who can extend them.
Additionally, we have to provide data about which types can extend the
sealed type, so it's not just a simple on/off type behavioral switch
(which I think is an antipattern for attributes based on my experience
in other languages that have them).

This is different from a return type `never`. A function which never
returns cannot meaningfully have any return type at all -- using
`void` or some other type with an attribute would be a lie.
Additionally, there isn't any meta-data to associate with the `never`.
I hope this comment doesn't digress into a conversation about `never`;
that isn't my point. I'm trying to provide more justification about
when I think attributes are appropriate, because I think they may be
appropriate here and I think it's useful to show how `never` is
different.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Benjamin Eberlei
On Sat, Apr 24, 2021 at 2:56 PM Pierre  wrote:

> Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit :
> > Hello Internals,
> >
> > I'm sending this email to open discussion about sealed classes,
> > interfaces, and traits feature for PHP 8.1.
> >
> > I have create a Draft RFC here:
> > https://wiki.php.net/rfc/sealed_classes
> > 
> >
> > A major concern for few people have been the syntax, in which it
> > introduces 2 new keywords into the languages, therefor, i have added a
> > section about alternative syntax which could be used to avoid this
> > problem.
> >
> > Regards,
> >
> > Saif.
>
> Hello,
>
> And why not using an attribute, such as in HackLang ?
>

+1 on this, I said the same on the "never/noreturn" RFC. There is a much
less invasive way to add new keywords/flags to functions by using
attributes.

Imho this decouples new features from the language and reduces the "risk"
of adding them to the language. That should increase the likeliness of it
getting accepted in my opinion.

>
> Regards,
>
> --
>
> Pierre
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>


Re: [PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Pierre

Le 24/04/2021 à 12:55, Saif Eddin Gmati a écrit :

Hello Internals,

I'm sending this email to open discussion about sealed classes, 
interfaces, and traits feature for PHP 8.1.


I have create a Draft RFC here: 
https://wiki.php.net/rfc/sealed_classes 



A major concern for few people have been the syntax, in which it 
introduces 2 new keywords into the languages, therefor, i have added a 
section about alternative syntax which could be used to avoid this 
problem.


Regards,

Saif.


Hello,

And why not using an attribute, such as in HackLang ?

Regards,

--

Pierre

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



[PHP-DEV] [RFC][Draft] Sealed Classes

2021-04-24 Thread Saif Eddin Gmati
Hello Internals,

I'm sending this email to open discussion about sealed classes, interfaces, and 
traits feature for PHP 8.1.

I have create a Draft RFC here: https://wiki.php.net/rfc/sealed_classes

A major concern for few people have been the syntax, in which it 
introduces 2 new keywords into the languages, therefor, i have added a 
section about alternative syntax which could be used to avoid this 
problem.

Regards,

Saif.




> Note: I'm sending this email again using a different mail client as the 
> previous one ended up in spam folder for most people