I was hoping to start some discussion regarding named parameters. I'm sorry if it's frowned upon to re-post or re-paste something, but I'm thinking that perhaps my email (with the subject Re: Hi) was overlooked on the list in whatever readers, so I'm going to post it again, this time with a better subject. My apologies if this is frowned upon, I'm just trying to bring up a discussion about this issue I'd like to see in PHP 6.

Once again I'd love to create an RFC for this, but I don't think I have permissions on the wiki to do that. What do I do to get those privileges granted to my wiki account?

==== original ====

... I've been a PHP developer for
a long time (and before that, C / C++ ) and as I saw code grow and
change, I developed design patterns to help ensure maintainability in
the long term. In fact, as a founder of a business (and not just a
programmer), I value the readability and maintainability of code even
more than things like elegance, expressiveness, or programmer talent,
because it scales better and is more robust, letting programmers get
up to speed.

Anyway I noticed that the following always seems to happen over time:
in any project, a set of functions and classes is created, which may
or may not become a reusable library. There is code that calls these
functions. Over time, the classes get more methods, and the functions
may be overloaded to handle more functionality. The classes are
designed to expand nicely, and nothing needs to be done. But the
functions start looking pretty bad after a few years, because of the
parameter mechanism. By necessity, the order of the parameters
corresponds to the time at which they are introduced, and not
something more logical. Providing defaults for the parameters does
very little to mitigate this. Experience has shown that hardly anyone
ever predicts at the outset how a library will evolve, and currently
function "interfaces" are something that needs to be planned carefully
at the start, or else can devolve into some nonsense that requires
calls like:

myFunc(3, 4, null, 4, 8, null, "blah")

Besides being hard to follow, it's also cryptic to the reader of the
call. We are not sure what the null or 4 corresponds to, without
looking up the function definition (perhaps in a tooltip in an IDE).

The solution is simple. I've gotten into a habit of defining almost
all my functions like this:

function myFunc($required1, $required2, array $optional = array()) { }

As the function's interface evolves over time, new required parameters
cannot be introduced (as it would break the old calls to the function,
which may be in the wild). However, functionality can be extended via
optional parameters. Also, the calls to the function always look much
cleaner:

myFunc(3, 4, array('clean' => true, 'name' => 'title'))

Inside the actual function implementation, I may very well just do:
extract($optional). The $optional array can override existing
parameters, etc... in fact, I can very easily set some defaults, with
either one of these two patterns:

$clean = true; $name = 'default'; extract($optional);

or the javascript-like way:

$defaults = array('clean' => true, 'name' => 'default');
extract(array_merge($defaults, $optional));

So why am I saying all of this? Well, PHP up until 4 had a reputation
for lots of bad coding style, spaghetti code, etc. With PHP 5 and
better OOP, this reputation has lessened, especially with the great
libraries out there (Zend Framework, Kohana, symfony, etc.) But there
is still a problem. We (or at least I) would want PHP 6's reputation
to be even better, and the reputation is largely based on how
maintainable and cost-effective the code is, which is written by
programmers actually using PHP. Blaming newbie programmers is one
thing, and may even have some truth to it (PHP is simple - thus
attracts newbies) but it's always good for a language to steer you in
the right direction by default, and make it easier to write
maintainable code.

PHP has a great opportunity to do this, by implementing a very simple
change, turning all current PHP 5 code, and all code that will be
written in the future, into maintainable code. Moreover, it won't
break any existing code, like some other additions to PHP 6 might do.
This one simple tweak will make PHP 6 code much more reusable and
maintainable, just like namespace support will potentially make future
PHP code more interoperable without having to write
Artificial_Namespace_Class, like ZF and PEAR do.

So here is my proposal. Let's have named parameters. Yes, I know this
has been brought up before and rejected -- although I don't know what
the discussion was, so I would like to have one in light of what I
said above. Other languages have elegant solutions to this ... python,
javascript, etc. and yes I realize that a common response is "PHP is
PHP and not those other languages". But this might be a short-sighted
response, as other languages may have winning features that really
make it possible for programmers to write better code, and develop
better coding and thinking patterns, at no cost, and we would do well
to consider whether PHP could benefit from a feature like that.

I propose we do two things in PHP 6:

1) Extend function call syntax and semantics so that providing
parameters to a function has exactly the same syntax as creating an
array. Namely:

myFunc(3, 4, 'a' => 'b', 'c' => 'd') would be possible, just like
array(3, 4, 'a' => 'b', 'c' => 'd')

COMPATIBILITY:

        This shouldn't break any userland code in earlier versions of PHP,
because current function calls are simply a subset of the proposed
functionality. They will continue to work in exactly the same way,
from the point of view of userland.

PROS:

        a) Makes understanding the language easier for everyone, since now
there is only one thing to remember rather than two (current docs are
a bit hard to grasp regarding references). Two concepts are unified
into one, reducing mind clutter. Passing parameters becomes like
creating an array, and references are handled nicely within this
unified paradigm.

        b) Most importantly, makes EVERY function and method extensible as I
described above. No more adding parameters ad-hoc in the order they
are dreamed up. Instead, they can be added as named parameters, just
like the $optional array I was using above. While programmers can
choose to use my design pattern, those that didn't plan out all future
versions of the function (let's face it, the majority) still get to
reap the advantage of this design pattern, simply via named
parameters. Leading to *vastly more maintainable code*, which is what
I am really advocating here.

        c) Calls to functions will no longer be cryptic, but actually
descriptive. Compare myFunc(3, 4, null, null, array(), 5) to myFunc(3,
4, 'max' => 5)

CONS:
        There is only one I can think of. Named parameters are superior to
parameters with default values (foo = "bar") in every way except one:
because the defaults are assigned within the function implementation,
they have to be documented separately (in DocBlocks, for example). I
had someone bring up the objection that code using this design pattern
would be less self-documenting. My response is that a) with magic
methods, PHP hardly encourages self documenting code anyway, and b)
the actual maintainability gains that result from sensible function
interfaces will far outweigh whatever negligible benefit one may get
from knowing parameter defaults from function signatures. If anything,
it'll cause more people to document defaults properly, using DocBlocks
or another method.

2) Extend func_get_args to be able to return associative arrays.

ANALYSIS:
        This shouldn't break existing function calls, and here's why. Old
versions of the function won't use this feature, so function calls to
them won't need to change, either. New versions of the function will
be written after this feature is introduced (i.e. in PHP6), so will be
aware of the possibility of named parameters. Old calls to new
versions of the function simply won't use the feature, so they won't
need to change, either. New calls to new versions of the function have
the option of using the feature, or not. So nothing is broken at all,
but new functionality is there for you to use in PHP6.

PROS:

        a) This once again makes PHP more elegant and unified. One of PHP's
most notorious / cool features is that it lets you use array() for
both numerically indexed arrays and associative arrays (a.k.a. maps,
hashes, dictionaries, etc.) Why not weave this into PHP function calls
as well? PHP is so function oriented. And this would give developers a
lot of expressive power while at the same time promoting better code
and the maintainability we talked about. I personally feel it's purely
awesome whenever an extension is able to achieve both of those.

        b) Lots of PHP programmers also work with Javascript. This would make
them happy -- they can use what they consider to be a very useful
coding pattern in JS (jQuery and most other popular frameworks use
it), and start doing it in PHP:

function myFunc($a, $b) {
        $id = uniqid();
        $title = 'People hi';
        extract(func_get_args()); // possibly overriding the parameters
}

CONS:

        a) Maybe there are some internal problems to implementing this, so
serious that it's infeasible?

        b) Will this break any PECL extensions? If so, are we planning to
maintain compatibility with all PECL extensions written for earlier
versions of PHP? Is it worth it to introduce this feature?

What do you guys think? I really want PHP 6 to rock and have an even
better reputation among businesses, programmers, etc.

Sincerely,
Greg Magarshak

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

Reply via email to