Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function overloading – one more time #1251

Closed
lerno opened this issue Jul 15, 2018 · 7 comments
Closed

Function overloading – one more time #1251

lerno opened this issue Jul 15, 2018 · 7 comments
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.

Comments

@lerno
Copy link

lerno commented Jul 15, 2018

As I understand it, function overloading is a no-go (see, for example #148 ).

With extended namespaced struct functions ( #1170 ) it's possible to circumvent part of the problem somewhat, but we're likely to end up with an informal naming of parameter types through the function name e.g. arrayCount(array) mapCount(map) stringCount(string) (with #1170, we would have been able to namespace, so array.count() map.count() string.count() would all have been valid new methods)

There is also the inelegance of things like max(f32, a, b) where type is carried around, even though it could be inferred. In this, we can contrast with Jai, where max(a, b) would be generated in pretty much the same way as Zig, but would not need the type parameter.

Another issue arises with the explicit type parametrization: consider complex types, rather than fundamental ones, e.g.: count(ArrayList([]const u8), list)... compare this to Jai's count(list).

I've looked through the proposals for improvements, and it feels like this is an underlying reason why many proposals get rejected.

Finally I want to mention that both using C macros or C++ templates we could easily write a MAX(a, b), or a count(iterable) function that works without passing the explicit type, but Zig, despite better compile time functionality can't do it due to missing overload.

@andrewrk
Copy link
Member

No function overloading, no functions with default values (#484)

@kyle-github
Copy link

I am not sure that C macros of C++ templates are good examples here. The first, C macros, may not be a good example because they are purely at a textual/source level and are difficult (when it is possible at all) to make typesafe etc. C++ is probably closer, but still can require you to specify the types.

If I look at your count example, it seems like passing in the type is closer to the Zen of Zig about being explicit. The example you give, count(ArrayList([]const u8), list) could easily be made more readable via a few intermediate const definitions.

Also, while it feels (and correct me if I understood this incorrectly!) that the major problem with max(f32, a, b) is that you specify the type, there is an advantage over max(a, b): the compiler can make sure that I am really passing f32 values. What I do (i.e. my source code) and my intent (the type I pass) must align.

@andrewrk andrewrk added proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. rejected labels Jul 16, 2018
@tiehuis
Copy link
Member

tiehuis commented Jul 16, 2018

To elaborate on the max example, Jai last I knew would allow you to specify which argument type deduction would be based on:

// Deduce T based on the first parameter
fn max(a: $T, b: T) T {}

// Deduce T based on the second parameter
fn max(a: T, b: $T) T {}

You can do left-most argument deduction with zig now as the following:

fn max(x: var, y: @typeOf(x)) @typeOf(x) {}

This however doesn't work since types are comptime values are evaluated left-to-right.

fn max(x: @typeOf(y), y: var) @typeOf(y) {}

@thejoshwolfe
Copy link
Contributor

We want identifiers to refer to a single definition rather than a set of possible overloads. If we had overloading, several things would get more complicated, like taking a pointer to a function, or rules for what identifiers are allowed to be declared in what scopes, or what overload is being called for all the possible instantiations of some generic parameters.

Function overloading is not necessary, and it causes lots of complexity and confusion.

@lerno
Copy link
Author

lerno commented Jul 16, 2018

I'm not advocating full function overloading but instead observing some problems:

  1. A need to informally namespace functions: array_count(...), map_count(...). This could be fixed with Allow struct method extensions #1170, as the struct could provide a formal namespace, e.g. Foo::compare(a, b), a.add(b) The current name standard for methods is especially poor for this: mapCountAsString(...) could be read as mapCount.asString() or map.countAsString() or count.mapAsString() unless there are formal rules.
  2. It prevents Unified Call Syntax #148 from even being considered on its own merits.
  3. Types appear to leak into the function definitions quite a bit.

@thejoshwolfe
Copy link
Contributor

Are you proposing a solution, or just discussing the topic?

@lerno
Copy link
Author

lerno commented Jul 17, 2018

@thejoshwolfe Discussing the topic since it appears to ripple through the entire design of the language.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

5 participants