Policy for procedural style in new additions

  114718
June 3, 2021 18:28 mel@dafert.at (Mel Dafert)
Hi internals,
After the RFC to add IntlDatePatternGenerator () was accepted, it was brought up that the duplication of
procedural and OO style was not necessarily/useful anymore.
This already has some (old) precedent - in 2012, UConverter was added to ext/intl
(https://wiki.php.net/rfc/uconverter) and in 2014 IntlChar 
(https://wiki.php.net/rfc/intl.char) - both of which only provide a class, but not the
procedural API.
This was also shortly discussed on the mailing list for IntlChar: 
https://externals.io/message/79146#79167 after which the procedural API
was dropped without much ado.

When I wrote the IntlDatePatternGenerator RFC, I was not aware that the
procedural API was viewed as deprecated, nor that there had been additions to
ext/intl that were purely OO.
In the thread after its vote, it was also suggested that we add a policy that
forbids new additions from adding duplicated APIs, and that OO style should
be preferred if possible. I am not sure if I am the best person to write such an RFC,
but I wanted to bring this to its own thread and provide the context I have dug up so
far.

The duplication of the OO and procedural API dates back to the addition of the intl
extension to core. There is some discussion about it in this thread from 2008:
https://externals.io/message/36775
(ignore the unrelated discussion about PHP6)
The main argument at this point was that OO in PHP is a new thing, and that while
the OO API is objectively better, the procedural API should also be there to
lessen the learning curve for existing PHP users that are not yet familiar with OOP.
I would argue that 13 years later, this argument no longer holds - anyone who
has used PHP at some point since then most likely has encountered classes.

One open question that still remains is what we do with the already existing
procedural API.
Should it be deprecated? Should it only be soft-deprecated, in that we mention in the
documentation that the OO style is preferred, but that the procedural API is 
not planned to be removed?
Should we just leave the procedural API as-is and live with the fact that some
classes have procedural counterparts
and some don't?
I would personally lean towards (at least soft-) deprecation just for consistency,
but I would like to hear what you would have to say.

Regards,
Mel
  114720
June 3, 2021 20:47 tekiela246@gmail.com (Kamil Tekiela)
Hi Mel,

I love this idea. We should definitely make it official that procedural
style API is unfavourable and should not be added to new classes.
On top of that, I would be in favor of deprecating all existing procedural
APIs.
- It's making it more difficult to maintain code in two variants
- It's making it difficult to maintain documentation
- It's confusing for users
- Procedural API is usually much more verbose than OO style
- The return values often do not match

OO style allows method chaining vs function nesting with procedural. The
only time when I ever saw any advantage to procedural style is when using
date_create(). Depending on what one is used to, procedural style can be
cleaner and more understandable.
echo date_diff(date_create('2000-01-01'),
date_create('2000-01-05'))->format('%R%a days');
vs
echo (new DateTime('2000-01-01'))->diff(new
DateTime('2000-01-05'))->format('%R%a days');

However, above examples are not apples to apples. When using date_create
with variable input, you must employ manual error checking as it won't
throw any errors like OO does. When you factor this in, the first example
becomes a nightmare and a gun to shoot yourself in the foot. It happened to
me.

So, maybe what we could do is slowly deprecate all procedural APIs, but
leave some exceptions as handy shortcut functions. If that's not possible,
then I wouldn't mind seeing all procedural APIs go away.

Regards,
Kamil
  114726
June 4, 2021 06:31 cschneid@cschneid.com (Christian Schneider)
Am 03.06.2021 um 22:47 schrieb Kamil Tekiela <tekiela246@gmail.com>:I love this idea. We should definitely make it official that procedural
> style API is unfavourable and should not be added to new classes. > On top of that, I would be in favor of deprecating all existing procedural > APIs. > - It's making it more difficult to maintain code in two variants > - It's making it difficult to maintain documentation > - It's confusing for users > - Procedural API is usually much more verbose than OO style > - The return values often do not match
While I understand your points and especially see the benefit for maintainers, I'm not a fan of make-everything-OO-with-exceptions. This leads to more exceptions creeping into otherwise exception-free code. I assume that some people don't see a problem with that but it can end up using exceptions for flow control which is frowned upon even by some exception enthusiasts. As soon as you start mixing ifs and exceptions it tends to get messy because you might even end up converting ifs to exceptions like try { $date = new DateTime($datestring); if ($limit > $maxlimit) throw new Exception(...); ... } catch (Exception $e) {} as opposed to if ($date = date_create($datestring) and $limit <= $maxlimit) ... I'm fine with new OO style APIs not providing a procedural equivalent but I'm wary about deprecating/removing existing ones. Final remark: I think neither procedural nor OO style is the right choice for everything. I believe it should be decided individually. - Chris
  114721
June 3, 2021 22:07 cmbecker69@gmx.de ("Christoph M. Becker")
On 03.06.2021 at 20:28, Mel Dafert wrote:

> After the RFC to add IntlDatePatternGenerator () was accepted, it was brought up that the duplication of > procedural and OO style was not necessarily/useful anymore. > This already has some (old) precedent - in 2012, UConverter was added to ext/intl > (https://wiki.php.net/rfc/uconverter) and in 2014 IntlChar > (https://wiki.php.net/rfc/intl.char) - both of which only provide a class, but not the > procedural API. > This was also shortly discussed on the mailing list for IntlChar: > https://externals.io/message/79146#79167 after which the procedural API > was dropped without much ado. > > When I wrote the IntlDatePatternGenerator RFC, I was not aware that the > procedural API was viewed as deprecated, nor that there had been additions to > ext/intl that were purely OO. > In the thread after its vote, it was also suggested that we add a policy that > forbids new additions from adding duplicated APIs, and that OO style should > be preferred if possible. I am not sure if I am the best person to write such an RFC, > but I wanted to bring this to its own thread and provide the context I have dug up so > far. > > The duplication of the OO and procedural API dates back to the addition of the intl > extension to core. There is some discussion about it in this thread from 2008: > https://externals.io/message/36775 > (ignore the unrelated discussion about PHP6) > The main argument at this point was that OO in PHP is a new thing, and that while > the OO API is objectively better, the procedural API should also be there to > lessen the learning curve for existing PHP users that are not yet familiar with OOP. > I would argue that 13 years later, this argument no longer holds - anyone who > has used PHP at some point since then most likely has encountered classes. > > One open question that still remains is what we do with the already existing > procedural API. > Should it be deprecated? Should it only be soft-deprecated, in that we mention in the > documentation that the OO style is preferred, but that the procedural API is > not planned to be removed? > Should we just leave the procedural API as-is and live with the fact that some > classes have procedural counterparts > and some don't? > I would personally lean towards (at least soft-) deprecation just for consistency, > but I would like to hear what you would have to say.
I'd take a step at a time, and start with "prohibit introduction of new dual APIs" only. (Soft-)deprecation can follow in own RFCs, maybe for single extensions, or even single (groups of) functions. -- Christoph M. Becker
  114722
June 3, 2021 22:27 paul.crovella@gmail.com (Paul Crovella)
On Thu, Jun 3, 2021 at 3:07 PM Christoph M. Becker <cmbecker69@gmx.de> wrote:
> > I'd take a step at a time, and start with "prohibit introduction of new > dual APIs" only. >
That sort of RFC doesn't really buy anything. It'd take a 2/3 vote to override it which is the same as what it'd take to introduce a dual API in the first place. Drop the ceremony and just add a note to the wiki.
  114763
June 7, 2021 10:40 nikita.ppv@gmail.com (Nikita Popov)
On Thu, Jun 3, 2021 at 8:28 PM Mel Dafert <mel@dafert.at> wrote:

> Hi internals, > After the RFC to add IntlDatePatternGenerator () was accepted, it was > brought up that the duplication of > procedural and OO style was not necessarily/useful anymore. > This already has some (old) precedent - in 2012, UConverter was added to > ext/intl > (https://wiki.php.net/rfc/uconverter) and in 2014 IntlChar > (https://wiki.php.net/rfc/intl.char) - both of which only provide a > class, but not the > procedural API. > This was also shortly discussed on the mailing list for IntlChar: > https://externals.io/message/79146#79167 after which the procedural API > was dropped without much ado. > > When I wrote the IntlDatePatternGenerator RFC, I was not aware that the > procedural API was viewed as deprecated, nor that there had been additions > to > ext/intl that were purely OO. > In the thread after its vote, it was also suggested that we add a policy > that > forbids new additions from adding duplicated APIs, and that OO style should > be preferred if possible. I am not sure if I am the best person to write > such an RFC, > but I wanted to bring this to its own thread and provide the context I > have dug up so > far. > > The duplication of the OO and procedural API dates back to the addition of > the intl > extension to core. There is some discussion about it in this thread from > 2008: > https://externals.io/message/36775 > (ignore the unrelated discussion about PHP6) > The main argument at this point was that OO in PHP is a new thing, and > that while > the OO API is objectively better, the procedural API should also be there > to > lessen the learning curve for existing PHP users that are not yet familiar > with OOP. > I would argue that 13 years later, this argument no longer holds - anyone > who > has used PHP at some point since then most likely has encountered classes. > > One open question that still remains is what we do with the already > existing > procedural API. > Should it be deprecated? Should it only be soft-deprecated, in that we > mention in the > documentation that the OO style is preferred, but that the procedural API > is > not planned to be removed? > Should we just leave the procedural API as-is and live with the fact that > some > classes have procedural counterparts > and some don't? > I would personally lean towards (at least soft-) deprecation just for > consistency, > but I would like to hear what you would have to say.
I think that not adding new procedural mirror APIs is pretty uncontroversial at this point. I think one open question is regarding API additions to existing classes with a mirror API -- should we keep adding procedural functions in that case? The more interesting question here is whether we want to deprecate existing APIs. From a quick look, these are the extensions that provide procedural mirror APIs: date finfo intl mysqli oci8 (only partially) xmlwriter I don't think I'd want to blanket deprecate all of these. I do see value in some of the procedural APIs (okay, only date really) or at least historical importance (mysqli is a migration target for mysql, which was only procedural). I think if we want to deprecate these, it should be on a case-by-case basis. For example, I see very little value in the procedural intl APIs. One annoying factor here is that these mirror APIs were often added thoughtlessly and have design issues as a result. For example, xmlwriter_open_uri() makes sense, but XMLWriter::openUri() should clearly have been a static method, not an instance method. Similarly, mysqli_init() makes some sense, but mysqli::init() is entirely useless. Regards, Nikita
  114767
June 7, 2021 12:03 dik.takken@gmail.com (Dik Takken)
On 07-06-2021 12:40, Nikita Popov wrote:
> I think that not adding new procedural mirror APIs is pretty > uncontroversial at this point. I think one open question is regarding API > additions to existing classes with a mirror API -- should we keep adding > procedural functions in that case?
I guess maintaining consistency between the mirror APIs makes sense for as long as we still have those mirror APIs.
> The more interesting question here is whether we want to deprecate existing > APIs. From a quick look, these are the extensions that provide procedural > mirror APIs: > > date > finfo > intl > mysqli > oci8 (only partially) > xmlwriter > > I don't think I'd want to blanket deprecate all of these. I do see value in > some of the procedural APIs (okay, only date really) or at least historical > importance (mysqli is a migration target for mysql, which was only > procedural). I think if we want to deprecate these, it should be on a > case-by-case basis. For example, I see very little value in the procedural > intl APIs. > > One annoying factor here is that these mirror APIs were often added > thoughtlessly and have design issues as a result. For example, > xmlwriter_open_uri() makes sense, but XMLWriter::openUri() should clearly > have been a static method, not an instance method. Similarly, mysqli_init() > makes some sense, but mysqli::init() is entirely useless.
Deprecating the procedural APIs where it makes sense sounds like a great step into the right direction. Historical oddities in the OO APIs could be dealt with later. Regards, Dik Takken