Hi,
As I understand it, using Java-like function overloading in PHP is
undesirable due to hindrance in readability.
However I'd like to get an opinion on whether it would be received more
favourably if it could provide an actual performance enhancement over hand
managed implementation's of detecting argument differences with variadic
and func_get_args.
On to a more subjective argument, "naming things" is hard, and I think many
people would appreciate being able to reuse function/method names without
sacrificing type safety.
Any thoughts?
As I understand it, using Java-like function overloading in PHP is
undesirable due to hindrance in readability.
Besides it impacting, readability, it will also create a large impact on
performance.
Right now, functions (and methods) are looked up by their name only. In
order to support function overloading, the argument's types also need to
be taken into account. In C++, it works by mangling function names by
adding markers for types, such as:
_ZN4HPHP34c_MongoDBDriverCursor_ni_getServerEPNS_10ObjectDataE
which means:
HPHP::c_MongoDBDriverCursor_ni_getServer(HPHP::ObjectData*)
But unlike in C++, this needs to be done at runtime, and every time a
function is called because PHP is dynamically typed, and not statically.
For example:
myOverLoadedFunction(string $s, long $l, Weather $w)
could be:
myOverLoadedFunction_s_l_cWeather
or something like that.
Doing these conversions would mean (in the most simple way), that for
each function call, a string needs to be manipulated to create the
mangled function name to lookup for in a hash, where right now, they
only have to be strtolower()
'ed (because of case insensivity).
And then you need to do something sensible when no types have been
defined.
cheers,
Derick
Derick Rethans wrote:
As I understand it, using Java-like function overloading in PHP is
undesirable due to hindrance in readability.Besides it impacting, readability, it will also create a large impact on
performance.Right now, functions (and methods) are looked up by their name only. In
order to support function overloading, the argument's types also need to
be taken into account. In C++, it works by mangling function names by
adding markers for types, such as:_ZN4HPHP34c_MongoDBDriverCursor_ni_getServerEPNS_10ObjectDataE
which means:
HPHP::c_MongoDBDriverCursor_ni_getServer(HPHP::ObjectData*)
But unlike in C++, this needs to be done at runtime, and every time a
function is called because PHP is dynamically typed, and not statically.For example:
myOverLoadedFunction(string $s, long $l, Weather $w)
could be:
myOverLoadedFunction_s_l_cWeather
or something like that.
Doing these conversions would mean (in the most simple way), that for
each function call, a string needs to be manipulated to create the
mangled function name to lookup for in a hash, where right now, they
only have to bestrtolower()
'ed (because of case insensivity).And then you need to do something sensible when no types have been
defined.
And we would run into similar issues as with the union types with regard
to weak typing.
--
Christoph M. Becker
And we would run into similar issues as with the union types with regard
to weak typing.
This is probably the biggest hurdle, IMO - regardless of the internal
implementation, you've got to define exactly how the feature would work
in the language itself.
A quick example off the top of my head (there are many other edge cases
to cover):
class A {
public function foo($bar) { echo 0; }
public function foo(string $bar) { echo 1; }
public function foo(int $bar) { echo 2; }
}
class B extends A {
public function foo(float $bar) { echo 3; }
}
(new A)->foo(1.5);
(new B)->foo(1.5);
Regards,
Rowan Collins
[IMSoP]
In your example, the output may be:
0
3
float, int and string all share the same row on an upside down pyramid,
with $bar, being dynamic, at the bottom.
With regards to union types, it could work exactly like the latest
Multi-Catch feature.
And we would run into similar issues as with the union types with regard
to weak typing.This is probably the biggest hurdle, IMO - regardless of the internal
implementation, you've got to define exactly how the feature would work in
the language itself.A quick example off the top of my head (there are many other edge cases to
cover):class A {
public function foo($bar) { echo 0; }
public function foo(string $bar) { echo 1; }
public function foo(int $bar) { echo 2; }
}
class B extends A {
public function foo(float $bar) { echo 3; }
}(new A)->foo(1.5);
(new B)->foo(1.5);Regards,
Rowan Collins
[IMSoP]
float, int and string all share the same row on an upside down pyramid, with $bar, being dynamic, at the bottom.
OK, so take away the dynamic case, and assume the caller is in weak
mode. Now you have a second case where you need priorities between the
types.
Or consider this code, which is already valid:
class A { function foo($bar) { echo "A: $bar"; } }
class B { function foo(int $bar) { echo "B: $bar"; } }
(new B)->foo(1.5); // B: 1
Or we could construct similar examples with parent and sub-classes as
the type constraint of $bar. And so on.
I tried to stress that this is an example of one detail among many that
would need to be worked out; I wasn't looking for a single answer.
Perhaps we would need to add a new keyword (or a native annotation?) to
mark that a function was overloaded, so that existing inheritance didn't
accidentally become overloading.
To my mind, this would add a lot of complexity to the language, and I'm
not convinced of the gain. If you want to avoid dynamically checking
variable types, you can always just provide separately named methods for
separate cases.
Regards,
Rowan Collins
[IMSoP]
Yes, I can see what you mean. Should a float prefer a string or an int? I
don't know.
That would be a issue unless an additional method of prioritising were
involved. Perhaps if attributes get in there will be a solution:
<<Overloaded(1)>>
function foo(int $a) {}
<<Overloaded(2)>>
function foo(string $a) {}
Yet as complicated as overloading would be to begin with, this I feel would
make it even worse lol.
Just for clarifies sake I'll explain briefly what I feel the benefits are,
and perhaps we can see if it's worth discussing further:
-
No need to conjure new names. A biggy IMO.
-
A new way of overriding. If you want to override a base class method by
capturing an argument of lower bounds, you won't need to do an instance
check and decide on super or alternative code. -
Performance enhancement over emulated overloads such as __call, variadic
and anonymous arguments.
Regarding the last point, I've mocked up a basic benchmark to illustrate
the difference in performance when comparing emulated overloading with
alternative functions.
I expect native support for overloading to be somewhere in between the
results of the two tests.
https://gist.github.com/orolyn/ff70f512efee36d402d1fc4fbc8f0521
float, int and string all share the same row on an upside down pyramid,
with $bar, being dynamic, at the bottom.OK, so take away the dynamic case, and assume the caller is in weak mode.
Now you have a second case where you need priorities between the types.Or consider this code, which is already valid:
class A { function foo($bar) { echo "A: $bar"; } }
class B { function foo(int $bar) { echo "B: $bar"; } }
(new B)->foo(1.5); // B: 1Or we could construct similar examples with parent and sub-classes as the
type constraint of $bar. And so on.I tried to stress that this is an example of one detail among many that
would need to be worked out; I wasn't looking for a single answer.Perhaps we would need to add a new keyword (or a native annotation?) to
mark that a function was overloaded, so that existing inheritance didn't
accidentally become overloading.To my mind, this would add a lot of complexity to the language, and I'm
not convinced of the gain. If you want to avoid dynamically checking
variable types, you can always just provide separately named methods for
separate cases.Regards,
Rowan Collins
[IMSoP]
Hi,
Others have already raised good technical points (performance, how to
distinguish when we have dynamic/weak typing), but I'd like to offer
another argument against it, that is, that even if it were possible we
might not want overloading anyway.
From my perspective, function and method overloading in languages like
C++ or C# is useful for mainly two reasons: allowing omitting
unnecessary arguments (or, allowing providing additional, more specific
arguments), and accepting multiple types for arguments.
However, we already have solutions for both of these in PHP. PHP's
functions and methods can have optional parameters for which you do not
have to provide an argument, and because PHP is dynamically-typed, a
parameter can accept an argument of any type (and within the function
body discriminate between types) if it needs to. Also, PHP has fewer and
more generalised types than some other languages do, so where a C#
method might have overloaded versions taking a UInt8, UInt16, UInt32,
SInt8, SInt16 and so on, an equivalent PHP method might only take PHP's
single universal integer type.
Of course, this doesn't perfectly cover all the use cases of
overloading. You can't, for example, directly express in PHP that a
function takes one argument or another, but not both. That said,
however, I don't think this is necessarily a big problem: you can write
two functions with different names.
Having to write differently-named functions may well be a good thing,
too, speaking from having had to deal with APIs in languages where a
"single" method can have more than a dozen overloaded forms, each
behaving differently, yet they all look confusingly similar at the
call-site.
Anyway, thank you for asking!
--
Andrea Faulds
https://ajf.me/
Thanks. I only wanted some quick input into whether it was worth pursing
before I do something daft.. like build it :)
All I wanted to know was, if the technicalities could be worked out, and a
performance boost was possible, would people still dislike it. I'd still
like to see it added, but I admit it was a long shot.
Thanks,
Dominic
Hi,
Others have already raised good technical points (performance, how to
distinguish when we have dynamic/weak typing), but I'd like to offer
another argument against it, that is, that even if it were possible we
might not want overloading anyway.From my perspective, function and method overloading in languages like C++
or C# is useful for mainly two reasons: allowing omitting unnecessary
arguments (or, allowing providing additional, more specific arguments), and
accepting multiple types for arguments.However, we already have solutions for both of these in PHP. PHP's
functions and methods can have optional parameters for which you do not
have to provide an argument, and because PHP is dynamically-typed, a
parameter can accept an argument of any type (and within the function body
discriminate between types) if it needs to. Also, PHP has fewer and more
generalised types than some other languages do, so where a C# method might
have overloaded versions taking a UInt8, UInt16, UInt32, SInt8, SInt16 and
so on, an equivalent PHP method might only take PHP's single universal
integer type.Of course, this doesn't perfectly cover all the use cases of overloading.
You can't, for example, directly express in PHP that a function takes one
argument or another, but not both. That said, however, I don't think this
is necessarily a big problem: you can write two functions with different
names.Having to write differently-named functions may well be a good thing, too,
speaking from having had to deal with APIs in languages where a "single"
method can have more than a dozen overloaded forms, each behaving
differently, yet they all look confusingly similar at the call-site.Anyway, thank you for asking!
--
Andrea Faulds
https://ajf.me/
However, we already have solutions for both of these in PHP. PHP's
functions and methods can have optional parameters for which you do not
have to provide an argument, and because PHP is dynamically-typed, a
parameter can accept an argument of any type (and within the function
body discriminate between types) if it needs to. Also, PHP has fewer and
more generalised types than some other languages do, so where a C#
method might have overloaded versions taking a UInt8, UInt16, UInt32,
SInt8, SInt16 and so on, an equivalent PHP method might only take PHP's
single universal integer type.
This used the be the reason PHP worked so well ... one did NOT have to
worry about how a parameter was provided, and even today one is NOT
providing a binary 'int' even if you 'type' the value to be such. The
whole point of a compiled language being able to provide several
versions of the same function but with different binary parameter sizes
and types is hopefully something that will never trouble PHP? PHP is not
building a binary parameter stack for the function call.
function foo($a) {} is still the natural way of doing things if the
FIRST validation step is '$a between 1 and 10' and adding the 'int' does
nothing to change the work flow of handling $a in my book ... just loads
the process with additional checks which often have to be duplicated
internally anyway to maintain a proper flow through the process.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
Dominic Grostate wrote:
As I understand it, using Java-like function overloading in PHP is
undesirable due to hindrance in readability.However I'd like to get an opinion on whether it would be received more
favourably if it could provide an actual performance enhancement over hand
managed implementation's of detecting argument differences with variadic
and func_get_args.On to a more subjective argument, "naming things" is hard, and I think many
people would appreciate being able to reuse function/method names without
sacrificing type safety.
Another issue besides what has already been mentioned in other replies
is that PHP already has the concept of overloading[1]:
| Overloading in PHP provides means to dynamically "create" properties
| and methods. These dynamic entities are processed via magic methods
| one can establish in a class for various action types.
So at least another name would have to be chosen for either of both
concepts.
[1] http://php.net/manual/en/language.oop5.overloading.php
--
Christoph M. Becker