# Opinion on function/method name overloading

- Thread: https://externals.io/message/93831
- Original archive: https://news-web.php.net/php.internals/93831
- Started by Dominic Grostate on 2016-06-06T09:23:48+00:00
- Messages: 12
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #93831 — Dominic Grostate — 2016-06-06T09:23:48+00:00

URL: https://externals.io/message/93831#93831

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?

---

## #93833 — Derick Rethans — 2016-06-06T10:03:58+00:00

URL: https://externals.io/message/93831#93833 · In reply to: #93831

> 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

---

## #93835 — Dominic Grostate — 2016-06-06T10:31:41+00:00

URL: https://externals.io/message/93831#93835

Well I had given some thought to that :)

Instead of using mangled names and calculating the canonical name at
runtime, keep the name, but convert the function hashtable from a table of
op arrays into a table linked lists, of op arrays.

A non-overloaded function would be the only element in its list, so there
would be no need to process the entire signature, preserving the
performance of the current system.

In the event of an overloaded function, yes, there would be a performance
hit, but only if overloading is used.  And it should still be faster than
emulating overloading in PHP.

Lastly, a linked list allows on the fly additions and reordering when
organising the overloads by restrictiveness in descending order.




> 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

---

## #93836 — Christoph Becker — 2016-06-06T10:32:49+00:00

URL: https://externals.io/message/93831#93836 · In reply to: #93833

Derick Rethans wrote:

> 
> 
> > […]
> 
> 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.

And we would run into similar issues as with the union types with regard
to weak typing.

-- 
Christoph M. Becker

---

## #93837 — Rowan Collins — 2016-06-06T10:55:27+00:00

URL: https://externals.io/message/93831#93837 · In reply to: #93836

> 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]

---

## #93838 — Dominic Grostate — 2016-06-06T11:06:19+00:00

URL: https://externals.io/message/93831#93838 · In reply to: #93837

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.


> 
>
> > […]
>
> 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]

---

## #93839 — Rowan Collins — 2016-06-06T11:17:13+00:00

URL: https://externals.io/message/93831#93839 · In reply to: #93838

> 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]

---

## #93840 — Andrea Faulds — 2016-06-06T12:10:31+00:00

URL: https://externals.io/message/93831#93840 · In reply to: #93831

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/

---

## #93841 — Dominic Grostate — 2016-06-06T12:22:48+00:00

URL: https://externals.io/message/93831#93841 · In reply to: #93839

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


> 
>
> > […]
>
> 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]

---

## #93842 — Dominic Grostate — 2016-06-06T12:47:42+00:00

URL: https://externals.io/message/93831#93842 · In reply to: #93840

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/

---

## #93843 — Christoph Becker — 2016-06-06T13:17:04+00:00

URL: https://externals.io/message/93831#93843 · In reply to: #93831

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

---

## #93844 — Lester Caine — 2016-06-06T13:32:04+00:00

URL: https://externals.io/message/93831#93844 · In reply to: #93840

> 
> 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
