w3ctag/design-principles

Discourage overloading

Closed this issue · 16 comments

In particular the kind where subsequent arguments (both in terms of the amount of them and in terms of their type) depend on a prior argument. We have some of this in the platform and generally dictionaries or some such would have been better.

Do you have an example or two in your head already?

In a sense, optional arguments are related and could be seen as overloading, and that is quite common on the web platform.

Could you explain the reasoning behind this suggestion?

I’d also like the term “overloading” to be made more precise. Ideally, it would exclude type overloading functions’ individual parameters.

(For example, in JavaScript, TC39 is considering adding type overloading to Math.pow, making it return BigInts when given BigInt arguments. This is an attempt to match the precedent of JavaScript’s existing math operators such as **, whose parameters are already type overloaded.)

@kenchris I thought OP made it quite clear what kind of overloading was meant and it explicitly excludes ordinary optional arguments. So I'm not sure what clarification you are seeking.

@js-choi that's interesting. You could express most of that with unions in Web IDL so that seems fine, though you cannot really express the full intent of the argument and return value having to match in type, which might be nice for code generation and such.

@annevk We are seeking clarification on why OP sees this kind of overloading as harmful.

I see, because it's not very ideomatic, results in rather complex bindings, and more importantly makes it quite confusing what the actual signature of a method is when reading and writing code. It stems from an era when dictionaries were not yet a thing.

@littledan Hi Dan, do you know of people on the TC39 has discussed overloading in JavaScript and/or have opinions on this topic?

I agree that a lot of cases where overloading was helpful are now covered by dictionaries. However, for as long as positional arguments exist, overloading can still be useful and I'd be weary of discouraging it so generally. In fact, overloading is especially useful when combined with dictionaries, to turn one or more primitive argument(s) of an older API to a dictionary (e.g. addEventListener() or window.scrollBy()).

Overloading is also very useful for allowing the same method to work both for single cases and in aggregate, i.e. things like methodName(name, value) and methodName(namesAndValuesDictionary) or methodName(value) and methodName(arrayOfValues). Admittedly this pattern is less common in the web platform (though Chris, Tab, and I did adopt it in the Color API draft) but extremely common in libraries, and I'm not sure we should be adding a principle that goes against so much of what is considered good design among web developers.

Yes, it can be annoying to implement overloading in JS, but that's not a reason to avoid it, it's a reason to make it easier to implement. API design should be guided by usage, not implementation.

I wonder if we can instead isolate specific cases or styles of overloading which are problematic. @annevk you linked to three APIs above. Could you please elaborate on why these are bad, and how they would have been designed today?

more importantly makes it quite confusing what the actual signature of a method is when reading and writing code

Do you have an example for this?

How is addEventListener() an example of overloading given the definition in OP? For the examples I gave I would expect either dictionaries or separate method names to be used.

@kenchris:

@littledan Hi Dan, do you know of people on the TC39 has discussed overloading in JavaScript and/or have opinions on this topic?

FYI, I believe that @littledan may still be on leave of absence, so he may not reply for a while longer.

@sarahghp at Igalia has adopted some of @littledan’s prior projects, so she may be able to reply.

@tabatkins is also involved in both TC39 and Web Platform APIs, and @tabatkins and I have compared type overloading in JavaScript versus Web APIs, so they may also have insight.

I’ll also link to this thread on the TC39 General Matrix room and see if any other TC39 delegates have opinions.

Purely on the IDL authoring and tooling side, I agree with minimizing use of overloading (that is, literally the WebIDL overload syntax). It means that defining and linking to methods has to take the arglist into account in ways that are non-trivial and sometimes confusing for spec authors, and worse, almost never necessary so the few times it is it comes as an confusing surprise.

More generally, JavaScript does not have any native means of doing overloading in this sense -- you have to ignore the function's arglist and instead examine and dispatch by hand based on the arguments array -- so it's a pretty rare practice in JS APIs in my experience. (On the other hand, the things you can do in WebIDL without WebIDL overloads - optional arguments and unions - are pretty easy to do in JS, so they're common.) So I also believe that simply from a consistent-platform perspective, acknowledging that JS and its details are central to the web, we should also be avoiding the WebIDL overload feature whenever possible.

This seems like it's largely addressed by #372?

Anyway: I would like to particularly discourage the kind of overloading where the return type varies depending on the arguments, mostly because it makes it harder to read code and understand what it's doing (especially if the arguments are variables rather than constants).

Ooh yeah, #372 looks like it does pretty well.

Closing as addressed #372