Discussion:
[dart-misc] Method overloading (just an open discussion)
Gonzalo Chumillas
2016-07-15 17:36:57 UTC
Permalink
Hi guys,
What do you think about "function overloading"? In the words of Gilad
Bracha, author of Dart:

*There will be no type based overloading in Dart. If you need a different
variant of a method, create a method with a different name. This is what
anyone using a dynmaic language does anyway and they are better for it.
Even in language with mandatory types, type-based overloading is a bad
idea, creating brittleness and ambiguity.*

Source:
https://github.com/dart-lang/sdk/issues/49#issuecomment-108301493

But, what do you think? Is there a case in which "method overloading" is
justified? For example, let's consider the following two methods:

appendHtml(String html) {...}
appendElement(Element element) {...}


The previous code can be simplified by mixing the two functions into a
single one:

append(Object /* String|Element */ source) {
if (!(source is String || source is Element)) {
throw ArgumentError('Source must be String or Element');
}
// etc...
}


Is the previous example a "justified case"?
Thanks so much.
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
'Harry Terkelsen' via Dart Misc
2016-07-15 18:01:37 UTC
Permalink
I wouldn't call this type-based overloading. It would be type-based
overloading if you had (not legal dart):

append(String html) { ... }
append(Element element) { ... }

Instead, you have a method whose argument type is String|Element, which
(currently) can't be expressed by Dart's type system. I've seen functions
like this and think there are justified cases. The main downside is that if
someone calls append with an Object that is neither a String or an Element
then you won't get an error until runtime.

On Fri, Jul 15, 2016 at 10:37 AM Gonzalo Chumillas <
Post by Gonzalo Chumillas
Hi guys,
What do you think about "function overloading"? In the words of Gilad
*There will be no type based overloading in Dart. If you need a different
variant of a method, create a method with a different name. This is what
anyone using a dynmaic language does anyway and they are better for it.
Even in language with mandatory types, type-based overloading is a bad
idea, creating brittleness and ambiguity.*
https://github.com/dart-lang/sdk/issues/49#issuecomment-108301493
But, what do you think? Is there a case in which "method overloading" is
appendHtml(String html) {...}
appendElement(Element element) {...}
The previous code can be simplified by mixing the two functions into a
append(Object /* String|Element */ source) {
if (!(source is String || source is Element)) {
throw ArgumentError('Source must be String or Element');
}
// etc...
}
Is the previous example a "justified case"?
Thanks so much.
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups
"Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Philipp S
2016-07-16 20:34:45 UTC
Permalink
Post by Gonzalo Chumillas
append(Object /* String|Element */ source) {
if (!(source is String || source is Element)) {
throw ArgumentError('Source must be String or Element');
}
// etc...
}
The technical term for what you describe is "union type", and there has
already been quite a lot of discussion about it as far as I can
see: https://github.com/dart-lang/sdk/issues/4938
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Adam Stark
2016-07-18 17:52:36 UTC
Permalink
I'm sure there are justified cases. I see it a lot where visit(Object any
/*Foo | Bar */) kicks you off to visitFoo(Foo foo) and visitBar(Bar bar).
As you said, that's not enforced at type-checking time

I'm with the Dart authors. "True" function overloading can't really coexist
well with multiple inheritance, and Dart could be considered multiple
inheritance for this purpose. What if the object is both Foo and Bar? What
if it's status as Foo and/or Bar can't be decided at type-checking time?
For an example of single-inheritance languages with function overloading,
there's C#. It has drawbacks, even there: it's very difficult to figure out
which version of a function will be called without an IDE for instance.
Even some proper single inheritance languages such as Vala, choose not to
allow overloading for this reason.
Post by Gonzalo Chumillas
append(Object /* String|Element */ source) {
Post by Gonzalo Chumillas
if (!(source is String || source is Element)) {
throw ArgumentError('Source must be String or Element');
}
// etc...
}
The technical term for what you describe is "union type", and there has
https://github.com/dart-lang/sdk/issues/4938
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups
"Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Gonzalo Chumillas
2016-07-20 00:47:42 UTC
Permalink
This is the most convincing reply I have read. Thanks.

I also decided not to use "union types" to enhance the readability of the
source code. For example:

// append what? A string, an element, a horse?
final myVar = someMysticFunction();
append(myVar);


// Ok!
final myVar = someMysticFunction();
appendHtml(myVar);
Post by Adam Stark
I'm sure there are justified cases. I see it a lot where visit(Object any
/*Foo | Bar */) kicks you off to visitFoo(Foo foo) and visitBar(Bar bar).
As you said, that's not enforced at type-checking time
I'm with the Dart authors. "True" function overloading can't really
coexist well with multiple inheritance, and Dart could be considered
multiple inheritance for this purpose. What if the object is both Foo and
Bar? What if it's status as Foo and/or Bar can't be decided at
type-checking time? For an example of single-inheritance languages with
function overloading, there's C#. It has drawbacks, even there: it's very
difficult to figure out which version of a function will be called without
an IDE for instance. Even some proper single inheritance languages such as
Vala, choose not to allow overloading for this reason.
Post by Gonzalo Chumillas
append(Object /* String|Element */ source) {
Post by Gonzalo Chumillas
if (!(source is String || source is Element)) {
throw ArgumentError('Source must be String or Element');
}
// etc...
}
The technical term for what you describe is "union type", and there has
https://github.com/dart-lang/sdk/issues/4938
--
For other discussions, see https://groups.google.com/a/dartlang.org/
For HOWTO questions, visit http://stackoverflow.com/tags/dart
To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups
"Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
'Bob Nystrom' via Dart Misc
2016-07-20 16:13:34 UTC
Permalink
Post by Adam Stark
I'm with the Dart authors. "True" function overloading can't really
coexist well with multiple inheritance, and Dart could be considered
multiple inheritance for this purpose.
It can, it's just more complex. C++, Java, and C# all basically have to
tackle this.
Post by Adam Stark
What if the object is both Foo and Bar?
You basically need to have a rule to determine which takes precedence, and
report an "ambiguous overload" error at compile time if there isn't a total
order between all types. It can be unintuitive, but it's not intractable.
Post by Adam Stark
What if it's status as Foo and/or Bar can't be decided at type-checking
time? For an example of single-inheritance languages with function
overloading, there's C#. It has drawbacks, even there: it's very difficult
to figure out which version of a function will be called without an IDE for
instance.
Yes, overloading really does add a lot of complexity, especially once you
mix in type inference and generic methods. (C# does both.) Overload
resolution isn't simple. At the same time, it does seem to work for most
users most of the time, even when they don't have a precise understanding
of the rules.

In most cases, overloading is used for unrelated types where the resolution
is obvious.

Personally, I do think overloading is worth the complexity. It untangles a
few nasty corner cases. For example, you occasionally want to implement the
same generic interface twice with different type parameters. Like:

class Complex implements Comparable<Complex>, Comparable<num> {
// ...
}


There's no single precisely typed compareTo() method that satisfies both of
those interfaces if you can't overload. You can punt by defining
compareTo(Object
o) or compareTo(dynamic d) but that leads to an API that's too loose for my
taste. It also forces you to distinguish the cases manually in the method
body at runtime. That's ugly and can have a performance impact.

Cheers!

– bob
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Continue reading on narkive:
Loading...