Links to sites that have DDoS protections are marked as failed

More and more sites have DDoS or anti spam protections like Cloudflare DDoS Attack Protection or Godaddy that makes link checker fail on these links (server returns 502 code for instance if you are not an actual browser)
Only way for the moment to me is to exclude the sites.
But in the future we will have more and more site using these tools and link check will be only able to check internal links.
We have to figure out if we have any technical solution to this issue and see how to implement it.
All suggestions are welcome in the comments.
Thanks.

I've been suggested to try using a real browser in these specific failure cases and https://github.com/puppeteer/puppeteer may help. To investigate.

Cloudflare for instance displays a captcha (click to say you are not a robot) to solve as a security before the page is reached. So even with a puppeteer controlled browser it would ne help solving it. I would be too easy ;)
And we can't implement all the security methods of all web providers. Here it's a CloudFlare one but it will evolve and others will create new ways to secure, it's an endless race.

It might be advantageous to extend MLC enable/disable via annotation to include outcomes that mark as success/fail. I could see an annotation along the lines of markdown-link-check-status: ddos as a means by witch to describe an expected behavior; it would permit all other statuses to be checked. This extends to abnormal status codes too-- it would be nice to expect a link to return say a 403 since it isn't authenticated.

Is expecting a link to return a 403 a way to make the site stronger, not sure. The goal of MLC is to help having non broken links. If we hide the issue behind checking an error code that could be anything else including a real issue, that may not help. it can be a 403 because of ddos protection at first but then really become an access denied one and we won't notice.
I wonder if MLC outputting a list of links to manually check at the end would be ok. Like an exclude comment, it would be a manual check comment on a link and it would make listing of links to check possible for MLC but also would document that in the MD code. It's pretty similar to what you suggest with your annotation but will not trigger any real link checking and will never make the tests fail. It's exclude but still keep it in the test list... Not sure what I wrote is very clear though 😄

I’d say that providing a means to define a “good” link is in the spirit of MLC. There are occasions where it is necessary to redefine good and extending the exclude framework to permit that makes the tool more flexible. I chose 403 specifically, it is a scenario in which the designation exists but MLC is unauthenticated. I actually have a use case for it personally on my family intranet site. I wish to verify that the remote document would succeed if authenticated but not add credentials to the source. There are potentially additional scenarios where defining an alternate status code might be beneficial to the user— HTTP status is a suggestion not the law.

You totally had my approval at "my family intranet site" 🤯 😉
Extending the exclusion system may be fine but then we have to make sure users understand that this could generate false negatives (instead of currently have false positives). The output in the log have to be clear that the link was not completely verified and that they should check manually to make sure.

It might be worthwhile investigating the headers that MLC sends with each request. I had a link report "bad" (403) that definitely was not, turns out it was denied by my mod_security setup on a generic rule for not sending an Accept header (log entry sanitized):
[Thu Dec 17 19:48:52.040963 2020] [:error] [pid 11065:tid<PHONE_NUMBER>26528] [client <IP_ADDRESS>:56384] [client <IP_ADDRESS>] ModSecurity: Access denied with code 403 (phase 2). Operator EQ matched 0 at REQUEST_HEADERS. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_21_protocol_anomalies.conf"] [line "47"] [id "960015"] [rev "1"] [msg "Request Missing an Accept Header"] [severity "NOTICE"] [ver "OWASP_CRS/2.2.9"] [maturity "9"] [accuracy "9"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "example.com"] [uri "/do-not-track.txt"] [unique_id "X9wKhFxlGZj7qGQp7uBz5wAAAJU"]

@cadeef could you post what your modsec would have accepted?

The issue was the Accept header was missing from the request completely. A standard Accept: */* from MLC would likely do the trick. MDN Header Reference

Should we modify link-check to add this as a default or only document it here for users to add the header in options if needed? (I tend to prefer adding the default in link-check)

Should we modify link-check to add this as a default or only document it here for users to add the header in options if needed? (I tend to prefer adding the default in link-check)

But anyway it doesn't seem to be enough (would be too easy) for Cloudflare DDoS protection se for instance on this page https://metamask.zendesk.com/hc/en-us/articles/360015488991-Sending-Ether-New-UI-
There's no easy way obviously...
We need to keep improving Web fabric as broken links are bad for the Web, it makes its original purpose fail. Having a free interconnected network where everyone is equally able to access data... it's less and less true every day, but I keep thinking we have to help finding ways to prevent total failure to happen.
Here are some thoughts about things we might do here (or in Link-check):

When the link returns a 403, try to fallback to a centralised big company API https://developers.google.com/webmaster-tools/search-console-api/v1/getting-started#curl-usage
add a warning level to the logs. Will not fail the build but will display a list of links to manually check.

But anyway it doesn't seem to be enough (would be too easy) for Cloudflare DDoS protection se for instance on this page https://metamask.zendesk.com/hc/en-us/articles/360015488991-Sending-Ether-New-UI-
There's no easy way obviously...
We need to keep improving Web fabric as broken links are bad for the Web, it makes its original purpose fail. Having a free interconnected network where everyone is equally able to access data... it's less and less true every day, but I keep thinking we have to help finding ways to prevent total failure to happen.
Here are some thoughts about things we might do here (or in Link-check):

When the link returns a 403, try to fallback to a centralised big company API https://developers.google.com/webmaster-tools/search-console-api/v1/getting-started#curl-usage
add a warning level to the logs. Will not fail the build but will display a list of links to manually check.

Should have been more clear in my initial comment, I was doubtful the change would make a difference with Cloudflare. Projects of MLC's nature will continually be on the losing end of the request inspection cat and mouse.
Shoring up the request profile for MLC would likely eliminate some existing edge cases (like mine with standard mod_sec rules), but it will always be a chase. WAFs evolve constantly by design.
I'd argue it's worthwhile, at least in the short term, to patch low hanging fruit that maintains the standard user experience without additional annotation.
An exception framework, with toggleable handling, would be welcome as I've eluded before, but it creates additional complexity. Care in implementation would be necessary to ensure that simplicity of the primary cause (dead simple, bolt-on markdown link checking) is maintained.
I like the idea of optionally punting to a headless third-party service in the event of failure, but it opens up a can of worms (availability, privacy, support) that would need to be carefully navigated.

Should have been more clear in my initial comment, I was doubtful the change would make a difference with Cloudflare. Projects of MLC's nature will continually be on the losing end of the request inspection cat and mouse.
Shoring up the request profile for MLC would likely eliminate some existing edge cases (like mine with standard mod_sec rules), but it will always be a chase. WAFs evolve constantly by design.
I'd argue it's worthwhile, at least in the short term, to patch low hanging fruit that maintains the standard user experience without additional annotation.
An exception framework, with toggleable handling, would be welcome as I've eluded before, but it creates additional complexity. Care in implementation would be necessary to ensure that simplicity of the primary cause (dead simple, bolt-on markdown link checking) is maintained.
I like the idea of optionally punting to a headless third-party service in the event of failure, but it opens up a can of worms (availability, privacy, support) that would need to be carefully navigated.

I agree with your comments. DDoS protection on websites is something I have more and more issues with though... Maybe it's specific to the domain I work in (blockchain) but I think it's, like spam, something we will have to live with... and it will break the basic fabric of the Web. Is ti the role of MLC to fix this? Absolutely not, of course, but can we provide tools to help users to deal with that? I think so.
What tools? I'm not sure.
third party api use could for instance be optional and disabled by default. It may be an addon or something.
I think MLC has to evolve anyway. If we want ti to remain a small script, we will end with something that will be useless at some point. If we build a proper software, with extension capabilities by design, we will be able to improve and follow users needs.
I created a discussion about roadmap https://github.com/tcort/markdown-link-check/discussions/147
I can't force anyone to participate, but my opinion is that if we don't discuss the goals for MLC, we will only be able to deal with bug issues and some very use case specific improvements. Me need to lead this as a real product and don't be afraid to refactor. We can try to keep backward compatibility, but that's not a requirement for me if we provide at least the same features and even better ones. If the config file format has to change for that, I think it's not a blocker to many people.

I agree with your comments. DDoS protection on websites is something I have more and more issues with though... Maybe it's specific to the domain I work in (blockchain) but I think it's, like spam, something we will have to live with... and it will break the basic fabric of the Web. Is ti the role of MLC to fix this? Absolutely not, of course, but can we provide tools to help users to deal with that? I think so.
What tools? I'm not sure.
third party api use could for instance be optional and disabled by default. It may be an addon or something.
I think MLC has to evolve anyway. If we want ti to remain a small script, we will end with something that will be useless at some point. If we build a proper software, with extension capabilities by design, we will be able to improve and follow users needs.
I created a discussion about roadmap https://github.com/tcort/markdown-link-check/discussions/147
I can't force anyone to participate, but my opinion is that if we don't discuss the goals for MLC, we will only be able to deal with bug issues and some very use case specific improvements. Me need to lead this as a real product and don't be afraid to refactor. We can try to keep backward compatibility, but that's not a requirement for me if we provide at least the same features and even better ones. If the config file format has to change for that, I think it's not a blocker to many people.

Resolving #111 would help.

As an example of what you all long ago predicted, all links to GitHub Docs (https://docs.github.com/*) started failing for me within the past 13 hours with 403s. I am running markdown-link-check 3.10.0, and the issue is not related to a change in the version of markdown-link-check, so I assume GitHub enhanced their DDoS protections. I am a fan of the proposal to support expecting a 403 but an even bigger fan of the idea of escalation to a headless browser (and, if warranted, additionally escalating from a headless browser to a full browser). I don't think anyone would argue that Puppeteer is a panacea to the inherent arms race markdown-link-check finds itself faced with, but it has far more resources to keep up with changing expectations. I may have missed some pertinent issues, but these were the only two hits for DDoS in their issue tracker:

puppeteer/puppeteer#6436
puppeteer/puppeteer#7006

As suggested in the latter, puppeteer-extra-plugin-stealth can be used to dodge most DDoS protections. As an overall strategy, consolidating around a single (or small number of) large project(s) seems a solid one for the open-source community since we are much stronger together than separate.

I was wrong. The issue with links to GitHub Docs had nothing to do with DDoS, but rather GitHub evidently started requiring that clients accept compression. This .markdown-link-check.json resolved the issue for us.


Comparison with sish

From the awesome-tunneling list I found another one similar project https://github.com/antoniomika/sish with more stars.
It looks like serves the same purpose and also is written in Golang. Can you please help me to understand differences and  pros/cons? Maybe you guys can collaborate.
There was a demo service ssi.sh but author closed it because tired from abuses. Maybe you can deploy the instance on the remote.moe to make migration easier.
There is also SSH-J.com that also provides a free service and open source. It just uses a patched Dropbear ssh server
https://bitbucket.org/ValdikSS/dropbear-sshj/
But it can't forward HTTP/HTTPS but only SSH proxy.
UPD another one in Golang https://github.com/pcarrier/srv.us
Looks like there is no any others FOSS SSH services that we can at least selfhost.

It looks like serves the same purpose and also is written in Golang. Can you please help me to understand differences and pros/cons? Maybe you guys can collaborate.

I have never heard about sish but at a glance, it does seem a lot like remotemoe - and it even has more stars :)
I too would love to hear about their differences - maybe there's some inspiration to be had

There was a demo service ssi.sh but author closed it because tired from abuses. Maybe you can deploy the instance on the remote.moe to make migration easier.

I can relate, I too get some amount of abuse complaints.
I cannot see myself running an Sish instance on my infrastructure as it just serves the purpose of having an active instance of remotemoe to profile and debug with live users. As stated in the readme:
https://github.com/fasmide/remotemoe#what-its-not

thank you. I came to your repo from the Awesome Tunneling list and added a link to it into the Readme in #23. I hope it would be useful and users may found something better for their purposes than annoying you with feature requests.


404 page not working

Currently if i go to /asdasd it just says File not found.
Looks like the router.php file will need to updated for this.

Actually this is the fault of nginx, which does routing on the server, the router.php is just for local testing on developers machines, I'll fix it next time I log on to the server

We don't have a "nice" not found error page at all. This needs to be designed, added, and then configured in both Nginx and the router file.

Umm guys? We have http://beta.elementaryos.org/404. It just needs to be set up server-side.

"Go to Home Page" ?

Alright, developer-side is taken care of with the router.php. Just waiting for @fabianthoma to update the nginx config server-side and we'll be all set.

Done, 404 now works


Users -> Members fix

Slack changed from 'users' to 'members', this was causing repeated calls to users.list since it was never populated.
I think this fixes #22 as well.
Also fixes a perl warning related to next_cursor (Slack stopped sending empty cursors)

Thanks!


:How to export wallet" button problem.

This "how to export wallet" button is not showing as an option on all wallets. Only on sms wallets.

Also, the export download that you get after clicking "download" is not readable and the last link in the file sends you to this page:  https://swaponline.github.io/2fa_wallet.zip
See screenhot:

Also please remove empty space:

2h30min

@shendel please separate time counter for bug fixes and features because bug fixes are our job, this must be free


Add possibility to optionally provide username and password for git repository.

The user can now specify username and password to authenticate against the specified git repository. #4

Hi @warmuuh ,
I have added the ability to provide credentials to connect to git repository. Related issue is: #4 .
Please let me know if there's any issue with the PR.

Hi @shridharc
Thanks for your contribution, I have yet to find the time to resolve the merge conflicts to close the pr though


Include parameters with extractor

I will try to deploy this to k8s so we can test

socialmediamacroscope/netowrk-analysis-extractor:latest

Tested. I also tested locally with an extractor I am working on with parameters. Sent them correctly.


CopyBuffer() method of SoftwareBitmap to an array crashes when trimming is enabled

Describe the bug
When using the CopyBuffer() method of a SoftwareBitmap to copy the pixels to a byte array the app crashes with an "Invalid cast" exception if trimming is enabled
To Reproduce

Run attached repro project

SoftwareBitmapTrimRepro.zip
Expected behavior
Should work the same as without trimming enabled
Version Info
WindowsAppSDK 1.2
Additional context

It seems that the issue is caused by the WindowsRuntimeBuffer class (and related extension methods like AsBuffer() for arrays) when trimming is enabled. Workaround: Add a TrimmerRootDescriptor file with the following content:
<linker>
  <assembly fullname="Microsoft.Windows.SDK.NET">
    <type fullname="System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBuffer"/>
  </assembly>
</linker>


Example of possible makefile for mlpack examples

Signed-off-by: Omar Shrit<EMAIL_ADDRESS>

@rcurtin  I think this is a possible example for a Makefile. I only made it for one example, if it is good, I will copy it everywhere with minor modifications.

Maybe we could add this makefile to our CI tests.

Do we want to keep the current folder structure or do we want to put everything in the root directory? Depending on the decision, I think a single Makefile as all we need?

@zoq I would prefer to have separate Makefile by example. This will reduce the compilation time, and will be much easier to manage and debug. This is only a prototype, if you find it well I will only copy it for all examples.

Maybe we can make it work for other examples? Like point users to this makefile and we make sure it works across all examples, and a user could call make example-name and that's it?

@zoq I agree, that is a good point, this will reduce non-useful duplication of Makefiles. Let us have @rcurtin opinion on this?

@shrit thanks for writing this up!  I think I would agree that we should have one Makefile in each directory.  My impression is that a user will come along and look at an individual directory, not at the whole project.  But it seems like it would be easy to have the best of both worlds... just have a top-level Makefile call out recursively to all the subdirectories?
This is a really generic Makefile, which is nice because we could just drop it in other directories, but it might be a little hard to understand for people not too familiar with the (really weird!) Makefile language.  In some sense even the Makefile itself is an example, so I'd hope to keep it as simple as we can.  But I'm not sure exactly where the right level is.  The configurable parameters at the top are really nice, but maybe we can hardcode the sources and compilation commands, so we get something like this?
all: mnist_simple

# Probably best to keep the non-optional parts of linking hard-coded in the command?
# Maybe good to add $(INCLFLAGS) containing any -I directories in case mlpack is not installed but only built locally?
mnist_simple:
    # If you're not using the Armadillo wrapper, replace `-larmadillo` with linker commands for the
    # BLAS and LAPACK libraries that you are using.
    $(CXX) -o mnist_simple mnist_simple.cpp $(CXXFLAGS) $(LDFLAGS) -lmlpack -larmadillo -lboost_serialization

clean:
    @rm mnist_simple

Might be good to put a disclaimer at the top or something, too, that says "you might need to modify this to get it to work on your system, but it should work in most places", or something like that.  It's just an example after all, not meant to build in every possible place. :smile:
Anyway, let me know what you think, these are just my opinions.  We could go with something else if desired.

I agree, one makefile by example seems to be a good idea, with a recursive call for the entire project.
I have made it generic because I do not want users to touch the Target and OBJS. They can change only source files, and add libraries if they want to add new dependencies. I will try to remove some redundant staff and see what we can get.

I think it is ready to be deployed on other examples.

@rcurtin  This one seems to be working, I kept one rule. If it seems good to you, I will deploy these modifications on other examples

Nice, that seems to work.  It seems also like you could use += instead and CXXFLAGS everywhere?  Here's a slightly modified version that might be cleaner:
CXX := g++
CXXFLAGS += -std=c++11 -Wall -Wextra -O3 -DNDEBUG -fopenmp
# Use these CXXFLAGS instead if you want to compile with debugging symbols and without optimizations.
# CXXFLAGS += -std=c++11 -Wall -Wextra -g -O0

LDFLAGS := -fopenmp -L/home/ryan/src/mlpack/build/lib/    # if installed locally
INCLFLAGS := -I/home/ryan/src/mlpack/build/include/ -I/home/ryan/src/mlpack/build/deps/ensmallen-2.11.5/include/ #Add header directories for any includes that aren't on the default compiler search path.

CXXFLAGS += $(INCLFLAGS)

(Of course, you would want to include the default INCLFLAGS and LDFLAGS that you have already.)
I think that using += everywhere could mean that I could set some CXXFLAGS in my environment and have those propagate to the Makefile, which is nice:
$ CXXFLAGS="-fail" make
g++ -fail -std=c++11 -Wall -Wextra -O3 -DNDEBUG -fopenmp -I/home/ryan/src/mlpack/build/include/ -I/home/ryan/src/mlpack/build/deps/ensmallen-2.11.5/include/    -c -o mnist_simple.o mnist_simple.cpp
g++: error: unrecognized command line option ‘-fail’; did you mean ‘-fnil’?
make: *** [<builtin>: mnist_simple.o] Error 1

Anyway, up to you what you want to do.  Overall it looks great to me---want to apply that the changes to all the other Makefiles?  I think this PR is ready once you do that. :+1:

@rcurtin I think we can merge it now,

@rcurtin we can merge now

Thanks @shrit! :+1:


Update the readme.MD for macOS release

add build badge for macOS build.
add download link for macOS build.

LGTM


unreachable code

/mediapipe/framework/formats/location.cc: line 567
switch (location_data_.format()) {
case LocationData::GLOBAL: {
return Rectangle_f(0.0f, 0.0f, 1.0f, 1.0f);
break;   // <-- unreachable
}

Whoops. Will remove this in the next release. Thanks for reporting this issue.

This is solved in https://github.com/google/mediapipe/commit/2b58cceec9953f0d97059934f0de85dd60adbe9b. Closing it now.


transition.redirect: TypeError: Cannot read property 'filter' of null

Get an "TypeError: Cannot read property 'filter' of null" error while doing:
route: {
        activate: function (transition) {
            var that = this,
                token = localStorage.getItem('jwt-token');
            if (token || token !== null) {
                transition.redirect({
                    name: 'home',
                });
            } else {
                transition.next();
            }

        },
 }

The home component will show in the Vue Devtools after this but in the dom there is still the previous component.

I also met the same issue.
data says the transition is undefined.

The home component probably threw the error, and caused the router to abort transition.
Check the home component first.

Since no repro is provided, closing due to inactivity.

Cannot read property 'filter' of undefined
at VueComponent.filteredRows (Datatable.vue?acdb:295)
i getting this error how to slove is please suggest

Cannot read property 'filter' of undefined
at VueComponent.filteredRows (Datatable.vue?acdb:295)
i getting this error how to slove is please suggest

Maybe you should update to Vue 2.x and use the latest version vue-router.


Indicator/UO: Fix calculation of third ratio

Fix error where secondLow was used as denominator in calculation of third ratio.

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Bug fix

What is the current behavior? (You can also link to an open issue here)
The second low result is used in calculating the third ratio.

What is the new behavior (if this is a feature change)?
The third low result is used instead.

Other information:

great stuff, thanks!

I would love a unit test similar to this one: https://github.com/askmike/gekko/blob/develop/test/indicators/ema.js for the UO indicator as a follow up PR, if anyone wants to do that that would be great!


Update finagle-http, finagle-stats, ... to 20.9.0

Updates

com.twitter:finagle-http
com.twitter:finagle-stats
com.twitter:twitter-server

from 20.7.0 to 20.9.0.
I'll automatically update this PR to resolve conflicts as long as you don't change it yourself.
If you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.
Configure Scala Steward for your repository with a .scala-steward.conf file.
Have a fantastic day writing Scala!

Ignore future updates
Add this to your .scala-steward.conf file to ignore future updates of this dependency:
updates.ignore = [ { groupId = "com.twitter" } ]

labels: library-update, semver-minor

Codecov Report

Merging #1264 into master will not change coverage.
The diff coverage is n/a.

@@           Coverage Diff           @@
##           master    #1264   +/-   ##
=======================================
  Coverage   81.07%   81.07%
=======================================
  Files          55       55
  Lines        1009     1009
  Branches       42       42
=======================================
  Hits          818      818
  Misses        191      191

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a99efb5...a238c4b. Read the comment docs.


No support for color output

When using GHCI with colored output (-fdiagnostics-color=always), the syntax highlighted code isn't showed by ghcid. As example, running without colors, I can see the following warning (in black and white) in one source file:
bigsorting.hs:11:20: error:
    • Variable not in scope: line :: String
    • Perhaps you meant one of these:
        ‘line1’ (line 10), ‘lines’ (imported from Prelude)
   |
11 |   let count = read line :: Int
   |                    ^^^^

Forcing ghci to use colors with -fdiagnostics-color=always causes ghcid to display the following (note the missing last 3 lines):
bigsorting.hs:11:20: error:
    • Variable not in scope: line :: String
    • Perhaps you meant one of these:
        ‘line1’ (line 10), ‘lines’ (imported from Prelude)

This is affecting ghcid version v0.6.10 with GHCi 8.2.1 on a Mac OS 10.12.6. I tested and confirmed this behavior on both the native Mac Terminal app as well as on iTerm2.

This is a duplicate of #87.

Thanks @vaibhavsagar - very similar to #87, but this one is a different entry point into the problem - and one I'm inclined to tackle first.

@scarvalhojr - enough has changed that I'm going to assume this bug went away in the rewrites. If not, please test with HEAD (or after a release) and reopen. On the plus side, you now get colors.

Yes, I tested it with HEAD and it works like a treat. Thanks @ndmitchell


Major update

Added touch edit functionality, added auto save options, options to limit number of rows in edit mode and more, sortable columns, improved and corrected the table onWidgetUpdate behavior.

Hi @selva-bizzgit thanks for the contribution and making the package more efficient, as the changes are big it will take some time to review and merge.

Thanks for the feedback.
On Sun, 14 Jan, 2024, 12:18 am Aakash Pamnani, @.***>
wrote:

Hi @selva-bizzgit https://github.com/selva-bizzgit thanks for the
contribution and making the package more efficient, as the changes are big
it will take some time to review and merge.
—
Reply to this email directly, view it on GitHub
https://github.com/aakash-pamnani/dynamic_table/pull/6#issuecomment-1890698290,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/BEXYW5LHTLLZUPLVL6GOSNTYOLJHZAVCNFSM6AAAAABBXW3MR2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQOJQGY4TQMRZGA
.
You are receiving this because you were mentioned.Message ID:
@.***>


Is there a plan to build a platform for people to discuss, share their drawing ?

We have a Discord https://t.co/jWJMO0IcUu?amp=1 and Show & Tell Section in Discussions.

We have a Discord https://t.co/jWJMO0IcUu?amp=1 and Show & Tell Section in Discussions.


proposal: Go 2: function overloading

This has been talked about before, and often referred to the FAQ, which says this:
Method dispatch is simplified if it doesn't need to do type matching as well.
Experience with other languages told us that having a variety of methods with
the same name but different signatures was occasionally useful but that it could
also be confusing and fragile in practice. Matching only by name and requiring
consistency in the types was a major simplifying decision in Go's type system.

Regarding operator overloading, it seems more a convenience than an absolute
requirement. Again, things are simpler without it.

Perhaps, this was the an okay decision at the point of the initial design. But I'd like to revisit this, as I question the relevance of that to the state of Go today, and I'm not sure just adding a section in the FAQ fully justifies a problem.
Why?
Complexity level is low to implement it in Go
Function overloading doesn't have to complicate the language much - class polymorphism, and implicit conversions do, and that with functional overloading does so even more. But Go doesn't have classes, or similar polymorphism, and isn't as complex as C++. I feel in the spirit of stripping to simplify, the need for it was overlooked. Because overloaded functions, are, for all practical purposes, just another function with a suffixed internal name (except you don't have to think about naming it). Compiler analysis isn't too complicated, and literally every serious language out there has it - so there's a wealth of knowledge on how to do it right.
Simpler naming and sensible APIs surfaces
Naming things is one of the most difficult things for any API. But without functional overloading, this makes this even harder, and in turn encourages APIs to be named in confusing ways and propagate questionable designs so much that its repeated use makes it perceived to be okay.
I'll address some cases, going from debatable to the more obvious ones:

Case 1: Go's standard library is filled with functions such as this
  func (re *Regexp) FindAll(b []byte, n int) [][]byte { ... }
  func (re *Regexp) FindAllIndex(b []byte, n int) [][]int { ... }
  func (re *Regexp) FindAllString(s string, n int) []string { ... }
  func (re *Regexp) FindAllStringIndex(s string, n int) [][]int { ... }

I believe this is confusing and there is no way to know what the functions' intents really are, unless we read the docs. (This is a common pattern we've become accustomed to over-time, but still isn't convenient in any way). Even worse, by avoiding function overloading, the language itself is now unfortunately encouraging people to create APIs with insensible names.
With function overloading, this could be
  func (re *Regexp) FindAll(b []byte, n int) [][]byte { ... }
  func (re *Regexp) FindAll(s string, n int) []string { ... }
  func (re *Regexp) FindAllIndex(b []byte, n int) [][]int { ... }
  func (re *Regexp) FindAllIndex(s string, n int) [][]int { ... }

I think this is much nicer, and simplifies the API as its essentially now just FindAll and FindAllIndex. It can reduced, and this also has implications that go into auto-completion, and grouping it in the API docs, etc.
The other part of the redundancy in this specific example relates to generics or variant types, but that's out of scope of this issue.

Case 2: The above example is actually one of the better ones.
http package:
func Handle(pattern string, handler Handler) { ... }
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { ... }

We've used it long enough so that this API has been ingrained into us by habit as to what it does. But let's think about it from a pure semantic perspective for a moment. What does HandleFunc mean? - Does it mean "Handle the Func itself", or "Handle it using the func"?. While, the team has done what's best without the capability of overloading - It's still confusing, and it's a poor API design.

Case 3:
Even worse and absolutely horrendous examples include:
  func NewReader(rd io.Reader) *Reader { ... }
  func NewReaderSize(rd io.Reader, size int) *Reader { ... }

I'm astonished (and saddened) that this style even became popular and into the standard library. Does this really mean "create a new reader of size", or "create a new reader size" (that is, semantically - an integer)?. And this list doesn't just go on, it encourages user to utilize the same design which creates a nasty world rather quickly.

Better default patterns for APIs
Currently one of the patterns that's considered a good way to pass options into APIs is: "The functional options" pattern by Dave Cheney here: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis.
While it's an interesting pattern, it's basically a work around. Because, it does a lot of unnecessary processing, like taking in variadic args, and looping through them, lot more function calls, and more importantly it makes reusing options very very difficult. I don't think using this pattern everywhere is a good idea, with the exception of a few that "really fits the bill" and keeps its configurations internal. (Whether it's internal or not, is a choice that cannot be generalized).
The most common pattern that I'd think as a general fit would be:
type Options struct { ... opts }
func DefaultOptions() { return &Options }
func NewServer(options *Options) { ... }

Because this way, you can neatly reuse the structures, that can be manipulated elsewhere, and just pass it like this:
opts = DefaultOptions();
NewServer(&opts);

But it still isn't as nice as Dave Cheney's example? Because, the default is taken care there implicitly.
If there was function overloading, it basically can be easily reduced to this
func NewServer() { opts := DefaultOptions(); NewServer(&opts) ... }
func NewServer(options *Options) { ... }

This allows me to reuse the structures, manipulate them, and provide nice defaults - and you can also use the same pattern as above for APIs that fit the bill. This is much much nicer, and facilitates a far better ecosystem of libraries that are better designed.
Versioning
It also helps with changes to the APIs. Take this for instance https://github.com/golang/go/issues/21322#issuecomment-321404418. This is an issue about inconsistent platform handling for the OpenFile function.  And I find that a language like Rust has a much nicer pattern, that solves this beautifully - with OpenFile taking just the path, and everything else solved using a builder pattern with OpenOptions. Let's say hypothetically, Go decides to implement that. The perm fileMode parameter is a useless parameter in Windows. So, make it a better designed API, let's hypothetically assume to remove that param since now OpenOptions builder handles all of it.
The problem? You can't just go and remove it, because it would break everyone. Even with major versions, the better approach is first to deprecate it. But if you deprecate it here - you don't really provide a way to program to change it during the transition period, unless you bring in another function altogether that's named OpenFile2 - This is how it'll ended up without overloaded functions. The best case scenario is you find a clever way to name - but you cannot reuse the same good original name again. This is just awful. While this particular scenario is hypothetical - it's only so because Go is still in v1. These are very common scenarios that will have to happen for the libs to evolve.
The right approach, if overloaded functions are available - Just deprecate the parameter, while the same function can be used with the right parameters at the same time, and in the next major version the deprecated function be removed.
I'd think it's naive to think that standard libraries will never have such breaking changes, or to simply use go fix to change them all in one shot. It's always better to give time to transition this way - which is impossible for any major changes in the std lib. Go still has only hit v1 - So it's implications aren't perhaps seen so strongly yet.
Performance optimizations
Consider fmt.Printf, and fmt.Println and all your favorite logging APIs. They can all have string specializations and many more like it, that opens up a whole new set of optimizations possibilities, avoiding slices as variadic args, and better code paths.

I understand the initial designers had stayed away from it - but I feel it's time that old design decisions that the language has outgrown or, is harmful to the ecosystem are reopened for discussions - the sooner the better.
Considering all of this, I think it's easy to say that a tiny complexity in the language is more than worth it, considering the problems it in turn solves. And it has to be sooner than later to prevent newer APIs from falling into the insensible naming traps.
Edits:

Changed a few words which have incorrectly set an offensive tone to the issue. Thanks to those who pointed out, and my apologizes to anyone, whom I may have inadvertently offended - was not my intention.
Added versioning point
Added optimizations point
Better formatting

In Go a function can be assigned to a variable or passed as a parameter. If functions can be overloaded, how will programmers indicate which variant of an overloaded function they meant?

On 28 Aug 2017, at 18:45, Prasanna V. Loganathar<EMAIL_ADDRESS>wrote:
This has been talked about before, and often referred to the FAQ, which says this:
Method dispatch is simplified if it doesn't need to do type matching as well.
Experience with other languages told us that having a variety of methods with
the same name but different signatures was occasionally useful but that it could
also be confusing and fragile in practice. Matching only by name and requiring
consistency in the types was a major simplifying decision in Go's type system.
Regarding operator overloading, it seems more a convenience than an absolute
requirement. Again, things are simpler without it.
Perhaps, this was the an okay decision at the point of the initial design. But I'd like to revisit this, as much of this "experience with other languages" seems misguided. And I'm not sure just adding a section in the FAQ fully justifies a problem.
Why?
Function overloading doesn't really complicate the language - class polymorphism does, and that with functional overloading does so. But Go doesn't have class polymorphism. I feel in the spirit of stripping to simplify, the need for it was overlooked. Because overloaded functions, are, for all practical purposes, just another function (except you don't have to think about naming it). Compiler analysis isn't too complicated, and literally every serious language out there has - so there's wealth of info on how to do it right.
Naming things is one of the most difficult things for any API. But without functional overloading, this makes things harder, and in turn encourages APIs to be named horribly and propagate bad designs so much that its repeated use makes it perceived to be okay.
Go's standard library is filled with functions such as this
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllString(s string, n int) []string
func (re *Regexp) FindAllStringIndex(s string, n int) [][]int

I don't this is good API design in anyway. The naming is horrific. But avoiding function overloading, the GO language is now unfortunately encouraging people to create APIs with insensible names.
With function overloading, this could be
func (re *Regexp) FindAll(b []byte, n int) [][]byte
func (re *Regexp) FindAll(s string, n int) []string
func (re *Regexp) FindAllIndex(b []byte, n int) [][]int
func (re *Regexp) FindAllIndex(s string, n int) [][]int

I think this is much nicer, and simplifies the API as, its essentially now just FindAll and FindAllIndex. It can reduced, and this also has implications that go into auto-completion, and grouping it in the API docs, etc.
The other part of the redundancy in this specific example relates to generics or variant types, but that's out of scope of this issue.
The above example is actually one of the better ones.
http package:
func Handle(pattern string, handler Handler)
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
We've used it long enough so that this ridiculous API has been ingrained in our brains as to what it does. But think from a pure semantic perspective for a moment. Does it mean HandleFunc mean, "Handle the Func", or "Handle it using the func". It's confused, and it's very poor API design.
Even worse and absolutely horrendous examples include:
func NewReader(rd io.Reader) *Reader
func NewReaderSize(rd io.Reader, size int) *Reader

I'm astonished that this style even before popular and the idiomatic Go way. Does this really mean "create a new read of size", or "create a new reader size" (aka an integer semantically). And this list doesn't just go on, it encourages user to utilize the same design which creates a nasty world rather quickly.
This avoids, yet another pattern that isn't so great, but often touted as the epitome of good design - "The functional options" pattern. Well, that's a nice pattern that was made popular by Dave Cheney here: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
While it's a decent pattern, it's basically a work around. Because, it does a lot of unnecessary processing, like taking in variadic args, and looping through them, lot more function calls, and more importantly it makes reusing options very very difficult. (I think Gophers touting this pattern is really misguided because of this). And it also involves a lot more function calls - I can't, for the life of me think of that as good design for most general APIs with the exception of a few that "really fits the bill".
The most common pattern that I'd think as a general fit would be
type Options struct { ... opts }
func DefaultOptions() { return &Options }
func NewServer(options *Options) { ... }
Because this way, you can neatly reuse the structures, that can be manipulated elsewhere, and just pass it like this:
opts = DefaultOptions();
NewServer(&opts);
But it still isn't as nice as Dave Cheney's example? Because, the default is taken care implicitly. (Well, you can do this still with pointers for options on the heap, but that's again bad design that forces things on the heap).
If there was function overloading, it basically can be easily reduced this
func NewServer() { opts := DefaultOptions(); NewServer(&opts) ... }
func NewServer(options *Options) { ... }
This allows me to reuse the structures, manipulate them, and provide nice defaults.
This is much much nicer, and facilitates a far better ecosystem of libraries that are better designed.
I understand the initial designers had stayed away from it - but I feel it's time that bad design are reopened for discussions - the sooner the better.
Considering all of this, I think it's easy to say that a tiny complexity in the language is more than worth the problems it in-turn creates. Note that it doesn't solve anything new - it just fixes the problems of it's own doing).
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.

@davecheney - Solutions make to sure things are compatible, and the semantics of the language doesn't change beyond what it has to be, can be discussed. But I feel, it's only productive to do so, if the problem is acknowledged and there is a willingness for it to be solved. So, far, I've unfortunately only seen deflection and being just marked as unfortunate rather than to even attempt to solve it.
One of the reasons for me to open this, is for indicate the need for the discussion on a reasonable approach to this.
That being said, I can think of a few ways - the obvious one being to pass the signature along - which might seem rather tedious, but the compile can quite easily infer it - and in cases of ambiguity won't compile.

While the proposal author is completely entitled to any opinion, the form of its presentation makes me uncomfortable.
Random samples:

Function overloading doesn't really complicate the language...

Opinion, but presented like a fact.

I don't think anyone would call this as good API design in anyway.

Wrong, I do.

I think we can all agree that the naming is just horrific, ...

Wrong, I disagree.

We've used it long enough so that this ridiculous API has been ingrained in our brains as to what it does.

Using words like ridiculous with regard to someone's else work really doesn't help your case.
And so on.

Calling something badly designed is easier than demonstrating it by example. If I see FindIndexString, I know I have a string. In your proposal, I have to look further and continue using human cycles to determine which FindIndex I'm looking at. I generally read more Go than I write Go by an order of magnitude so that "String" suffix saves me quite a bit of time over the years.
I don't think the language will be improving as people start populating packages with overloaded functions. The proposal lacks a basis of its assertions that this design is ridiculous. The as-seen-on-TV tonality of the proposal doesn't help either.

@cznic My apologies. Disregarding some one else's work wasn't my intention. If I've come across so - I do apologize. However, my emphasis on the using the words "ridiculous", and "horrific" weren't to disregard them - but to indicate on the fact that they aren't the best design, that has over time has been accepted to be okay.
I strongly believe they are APIs such as this
    func NewReader(rd io.Reader) *Reader { ... }
    func NewReaderSize(rd io.Reader, size int) *Reader { ... }

are horrible APIs, that's highly misleading. I also recognize that there were created due to such restriction in the language. These are meant to disregard the work of those who created the APIs, but in order to insist on the restrictions of language that forced them to create so.
I do apologize if my words came out offensive, than to convey my intention correctly. Hopefully, we can look past that and into the actual problem. Cheers. :)

@as, The semantic meaning of FindIndexString is find the index string, not find the index from a string (which is what the API means). This is my point, it has been so common for things to be misguided, that it has become OKAY to do so - which is not good.

You are missing the point. There is no FindIndexString. The function is regexp.FindStringIndex. I did not initially correct your error--it was irrelevant to your proposal and my response to it.

@as, I would argue that reading a FindIndex conveys all the meaning, and even simplifies the code. It doesn't take anymore human cycles, as you already know that it find the index of the thing that you pass into it, regardless of what it is. The intent is very clear. And if you go ahead and change it to a byte representation above, the semantics are persevered as such with no changes.
However, though even if you need to know the exact type - let's face, we're not in the 80s. We have language tools that assist. Constraining a language because of these limitations seems counter-intuitive to me. Almost any decent editor with language support can take you right to the function. And lesser code that conveys intent is always cleaner. "FindIndex" is just lesser than "FindIndexString". And suffix 'String' semantically becomes an implementation detail, not just the intent.

@as, I don't believe I made a typo calling it FindIndexString. And I see, you've edited your comment, that removes where you claimed I made a typo. But this only makes my case.
FindStringIndex,  FindIndexString are all so confusing that it's common. Whereas FindIndex is obvious and very clear.

I've relabeled this as a proposal, but in fact there is no full proposal here.  Perhaps this discussion should be moved to the golang-nuts mailing list.
I understand that the goal is to first say that function overloading could be added to Go 2, and to then discuss how it might work.  But Go language changes don't work that way.  We aren't going to say it's OK in principle, and lets figure out the details.  We want to see how it really works before deciding whether it is a good idea.
Any proposal for function overloading needs to address how to handle cases like
func Marshal(interface{}) []byte
func Marshal(io.Reader) []byte

in which for a given argument type there are multiple valid choices of the overloaded function.  I understand that others will disagree, but I believe this is a serious problem with C++ function overloading in practice: it's hard for people to know which overloaded function will be selected by the compiler.  The problem in Go is clearly not as bad as the problem in C++, as there are many fewer implicit type conversions in Go.  But it's still a problem.  Go is intended to be, among other things, a simple language.  It should never be the case that people are confused about which function is being called.
And lest anyone produce a simple answer for the above, please also consider
func Marshal(interface{}, io.Reader) []byte
func Marshal(io.Reader, interface{}) []byte

@ianlancetaylor - Thanks. Correct me if I'm wrong, but I understood this to be more of a philosophical change than a technical one, and a controversial topic to start a proposal without some feedback.
Because, technically, as you said, Go doesn't suffer from the complexities of C++. In fact, both of the above that you stated can be easily solved with simply disallowing all implicit conversions while matching, and disallowing them to compile at all when in doubt of an ambiguity.
High-level steps:

Match concrete types -> if they're exact matches - function identified.
Match specific interfaces -> Check interface compatibility -> If compatible - refuse to compile, else function identified. (This disallows both the above cases, as io.Reader is compatible with interface{})
Match to interface{}, if and only if the matches above didn't succeed or error, and method and such a match exists.

The above matches are always only entered when an overloaded method exists - so the compiler effectively only pays these costs when needed.
This should work nicely, because, a large number of scenarios covered above simply deal with concrete types.
Allowed:
func Marshal(string) []byte
func Marshal(byte) []byte
func Marshal(io.Reader) []byte

Allowed:
func Marshal(string) []byte
func Marshal(byte) []byte
func Marshal(interface {}) []byte

(Future optimizations: This even opens up specializations for APIs like "fmt.Printf" which can be specialized for strings without unnecessary allocations)
Refuses to compile:
func Marshal(interface{}) []byte
func Marshal(io.Reader) []byte

Side-note: All this opens up room for some very easy optimizations by means of specializations for APIs like "fmt.Printf" for strings, etc without unnecessary allocations.

Would the suggested very easy optimization of Printf e.g. fmt.Printf(string, string) need to also duplicate and specialise the underlying interface{} functions that are used by fmt.Printf:
Fprintf, doPrintf, ... which also take an interface to not just allocate later?

@martisch - I wouldn't say duplicate, but of course, it will have to go all the way down.
The type assertion for the string which happens today, will have to be refactored into its own tiny method, which the underlying implementation for the specialization will have to directly call.

@prasannavl There's no doubt that it's possible to come up with rules that somehow handle overloaded functions (C++ can do it...). That said, there really is a complexity argument as @ianlancetaylor has mentioned already. As it is, a function or method is uniquely identified by its name, it is a purely syntactic operation. The benefit of that simplicity, which you may consider perhaps too simple, is not be underestimated.
There's one form of overloading which I believe you haven't mentioned (or perhaps I missed it), and which also can be decided syntactically, and that is permitting the same function (or method) name as long as the number of arguments is different. That is:
func f(x int)
func f(x int, s string)
func f()

would all be permitted together because at any one time, depending on the number of arguments it is very clear which function is meant. It doesn't require type information (well, almost, see below). Of course, even in this simple case we have to take care of variadic functions. For instance:
func f(format string, args ...interface{})

would automatically consume all the functions f with 2 or more arguments.
Overloading based on argument count is like adding the number of arguments to the function name. As such, it's easy to determine which function or method is called. But even in this simple case of overloading we have to consider situations such as:
f(g())

What if g() returns more than one result? Still not hard, but it goes to show that even the simplest form of overloading can quickly lead to confusing code.
In summary, I believe for this proposal to be considered more seriously, there's a couple of things missing:

A concrete detailed description of the overloading rules proposed with a discussion of special cases (if any).
One or multiple concrete examples of existing code where overloading would solve a real problem (such as making code significantly easier to read, write, understand, or whatever the criteria).

Currently, the proposal seems to lack the engineering salience to seriously considered. Keep in mind that unless you are planning to create an experimental compiler and eventually working code, someone else from the Go team will have to implement this proposal.
In order to do that, there needs to be a perceived benefit that outweighs the cost of putting the change into the language. Ignoring the chaff (e.g., ridiculous, horrible), you submit that the language designers did not know what they were doing. Not really a good start for a proposal.
You need to prove your problem is everyone's problem. Then you need to provide a solution that stands up to technical scrutiny. Then the powers that be decide if that solution is simple and coherent enough to make it into the language.

I think you are suggesting that it will be impossible to overload functions based on different interface types when it is the case that one of the interface types is assignment compatible with the other.  That seems like an unfortunate restriction.  It's already always possible to use a type switch to select different behavior at run time.  The only gain from using overloaded functions is to select different behavior at compile time.  It is often natural to handle different interface types in a different type, and there are plenty of examples in existing Go code of doing that at run time.  Being able to overload some types at compile time but not others seems to me to be a weakness.
I forgot to mention another problem you will need to consider when it comes to writing a proper proposal, which is that Go constants are untyped.
func F(int64)
func F(byte)
func G() { F(1) } // Which F is called?

Also it will presumably be possible to overload methods, not just functions, so it becomes necessary to understand the meaning of method expressions and method values when they refer to an overloaded method.

func F(int64)
func F(byte)
func G() { F(1) } // Which F is called?

Here the rule could possibly be to use the same default type constants have in short variable declarations, ie. F(int) (not listed in the example, so a compile error in this case)

@cznic consider this code
package foo
func F(int64)

package bar // in a different repo
import "foo"
func G() { foo.F(1) }

That works but then foo adds func F(byte). Now bar.G() no longer compiles until it's rewritten to use an explicit conversion.
There's also the case of embedding an interface an interface when they have overlapping overloads.

That works but then foo adds func F(byte). Now bar.G() no longer compiles until it's rewritten to use an explicit conversion.

Nice catch.

In Go a function can be assigned to a variable or passed as a parameter. If functions can be overloaded, how will programmers indicate which variant of an overloaded function they meant?

@davecheney I think this can be resolved using the type of the variable, to which a function pointer is assigned. Can you give an example?

func Add(int, int)
func Add(float64, float64)
g := Add
What is the type of g?

func (s S) F1()
func f(interface{ F1() })
func f(interface{ F2() })

var s S
f(s)

This works until S implements F2.

I think that every time I've wished for some form of function overloading, it is been because I was adding a new parameter to a function.
func Add(x, y int) int {}

type AddOptions struct {
  SendMailOnOverflow bool
  MailingAddress string // default: 1600 Amphitheatre Parkway 94093
}

// AddWithOptions exists because I didn't think Add would need options.
// If I was starting anew, it would be called Add.
func AddWithOptions(x, y int, opts AddOptions) int {}

The cost of adding a ...WithOptions function isn't very high, so this generally isn't a huge concern for me. However overloading where the number of parameters must differ, as mentioned by @griesemer, would admittedly be useful in this case. Some form of default value syntax would also serve.
// Add(x, y) is equivalent to Add(x, y, AddOptions{}).
func Add(x, y int, opts AddOptions = AddOptions{}) in {}

To echo @neild's comment, it seems like all of these cases would be better addressed by either simpler or more general features proposed elsewhere.
Case 1 is really two issues: []byte vs string (which already has a cluster of related issues, exemplified by https://github.com/golang/go/issues/5376), and Index vs. Value (which, as @cznic notes, is a reasonable API distinction).
Generics (https://github.com/golang/go/issues/15292) would address the issue more clearly than overloading, because they would make it obvious that the only difference is in the types (not other behaviors):
func <T> (re *Regexp) FindAll(b T, n int) []T { ... }
func <T> (re *Regexp) FindAllIndex(b T, n int) [][]int { ... }

Case 2 is arguably better handled (ha!) by sum types (#19412):
func Handle(pattern string, handler Handler | func(ResponseWriter, *Request)) {
	...
}

But it's not obvious that even those are necessary: HandleFunc is already a bit redundant with the HandlerFunc type.
Case 3 is the default-parameter case that @neild mentions.
func NewReader(rd io.Reader, size=defaultBufSize) *Reader { ... }

r := bufio.NewReader(r, size=1<<20)

We can already fake it today with a combination of varargs and structs, and we would be even closer if we could easily use a literal type for the optional arguments (#21496).
func NewReader(rd io.Reader, opts ...struct{ Size int }) *Reader { ... }

r := bufio.NewReader(r, {Size: 1<<20})

@ianlancetaylor , @griesemer - Doesn't https://github.com/golang/go/issues/21659#issuecomment-325396314 solve all of what you have mentioned? Infact, I think it pretty much addresses most of the following comments.
@griesemer  - Just the number of arguments is a good compromise, except the simplicity is not going to be what meets the eye, due to what you had already mentioned in dealing with interfaces. However, a pattern like what I suggested is a set of rules, that makes it possible, while still retaining a good amount of simplicity.
@ianlancetaylor

I think you are suggesting that it will be impossible to overload functions based on different interface types when it is the case that one of the interface types is assignment compatible with the other. That seems like an unfortunate restriction.

Yes, it is restricted. But I see no reason that overloading has to be "all or nothing". I think concrete type specializations and interface{} with non-compatible interfaces would solve most uses cases without complicating things and the 'ick' factor associated with dealing with complex interfaces.
Besides, even if later found a necessity for, which I doubt, it should be far easier to go from a limited set, to an all encompassing set, but not the other way around. Learning from the other languages, searching for a perfect solution is probably not going to take us far - It's going to end up like the case of generics - 10 years and counting.

@bcmills , I see you've provided a set of potential workarounds to the cases on the first section. Except for the first, pretty much all of them rely on language features that do not exist, at the moment. For the sake of the argument, let's hypothetically take that all of the proposed features work, and exists, with the exception of generics (Will come to this in a bit).
Considering that, your solutions arguably solves one scenario, but things like specialization optimizations, versioning that I've added in the Why section still cannot be addressed.
Now, generics will get you quite far, no doubt. But why do I not include it? It has been in 10 years of exploration and still no clear future map to it. 10 years is a long time. If the language designers are searching for a perfect solution, I don't think they're going to find it, unless they move forward with some real implementation. Take Rust, C# for example - they move with some form of nightly versions that experiment making the feature available to use to the community, and learning from real use cases of it. Here's it's nice to see occasional articles from people like @rsc saying they've learnt more every year. But, learnt and used that knowledge how? With all this extended experience and knowledge, at best, it would be marginally better than the above mentioned languages, at worst, the same. I see a decade and still no significant drive to solve the problem loose hope of counting on that feature for any practical purpose.

@prasannavl It seems plausible that the restrictions you suggest will solve some of the problems mentioned above.  But it introduces new problems, which I described as "an unfortunate restriction" and which @griesemer described as "a complexity argument", adding "the benefit of that simplicity, which you may consider perhaps too simple, is not be underestimated."
To put it another way: you can solve certain problems by adding restrictions.  But now everybody writing Go has to understand those restrictions.  One of the several goals of Go is to provide a simple programming language.  The rule "no overloads" is very simple.  The rule "overloads are OK except that certain somewhat complex cases are prohibited" is less simple.
In other words, I'm explicitly disagreeing with your suggestion that it is easier to go from a limited set to an all encompassing set.  It's is not easier, because the intermediate state is a language that is harder to understand.  All language decisions are a balance of benefits and costs.  Increasing the complexity of the language is a significant cost.  It must be balanced by a more important benefit.  I understand that you are in favor of overloading.  But ultimately it adds no power to the language; it just lets you reuse a name rather than inventing a new one.  To me the benefits seem relatively small, and the costs must therefore be relatively small.
Separately, I think you still haven't addressed method expressions and method values in the presence of overloading.  For that matter, I don't understand how they work with @griesemer's suggestion of overloading on the basis of argument count.  I think this matters in conjunction with the Go 1 compatibility rule, because it means that a program using a method expression or method value may unexpectedly break due solely to adding a new function overload.  And the same seems to apply to a reference to a function in any way other than calling it.  In other words, even if we do add function overloading, it may be impossible to overload an exported function or method in the standard library, or in any other library that cares about source code compatibility.  That seems to me to be a considerable obstacle that needs to be understood first, not later.

@ianlancetaylor Thank you for the brief - it helped me understand your approach to this better. To be honest, I almost want to agree with you on most of it.
However,

it just lets you reuse a name rather than inventing a new one. To me the benefits seem relatively small, and the costs must therefore be relatively small.

I'm rather of the opinion that you're under-estimating the benefits of naming things. While I don't want to put too much emphasis on the saying "there are only two problems in computing - naming things and cache invalidation" - I'm sure that you do recognize the value in it, and it didn't become a common cliche for no reason.
Naming things by itself probably doesn't add a lot of value. But naming propagates it's benefits and problems into the design of APIs, which in turn affects "discoverability". Language simplicity and ease of use of a language are two separate things. I, personally, come from a heavy C#, and C background. So, to me C is simple - but C# has far better ease of use, which makes it simpler for most general use cases. One of the largest lack I see coming from that world into Go is that it's API discoverability is painful at best. People who are used to a library tend to look past it's discoverability. However without actually spending a lot of time in the docs or more naturally, just drilling into the source code, it's very difficult to understand many libraries. The regex package is a good example, where to this day, I still get confused and find myself looking at this docs, despite it's repeated use, as opposed to a library like C#, which provides overloading. I do still remember my initial days at C# almost two decades ago, being able to navigate through the standard library with just it's fantastic naming, organization and docs provided through intelli-sense. Today, with the abundance of language tools, I would like to insist on the tooling being a part of the consideration in language design. For example, overloaded functions often, achieve one goal - and such can be grouped together, in auto-completion, etc, which shows much simpler completion lists, that are far more comprehensible, etc. There are many smaller side benefits that I feel many overlook.
It's human tendency that once we get used to something long enough, we tend to just get used to it. I could be wrong here, but it's my personal suspicion that many Go programmers tend to just "get used to it", and as such discard the value from that's 'derived' from better naming. It doesn't just change a name. It's changes the paradigm with which APIs are designed.
That aside, I completely missed method expressions - let me sleep over it.

So, to me C is simple - but C# has far better ease of use, which makes it simpler for most general use cases.

(Emphasises mine) This is the key. To me C# is an unusable mess. Also because name overloading. Arguing that overloading is better or not is pointless. It's just a personal preference. For me naming functions doing different things, because they have different arguments but still use the same name is making the language much harder to read and reason about, especially for someone else's code.

The regex package is a good example, where to this day, I still get confused and find myself looking at this docs, despite it's repeated use, as opposed to a library like C#, which provides overloading.

Do you mean by this, that it would be better for you if all the regexp matching functions had the same name? I must be misunderstanding you. (?)

@cznic - Haha, touche on the emphasis point.

For me naming functions doing different things, because they have different arguments but still use the same name is making the language much harder to read and reason about, especially for someone else's code.

I don't think I ever claimed to have functions overloaded for doing different things. It's well accepted that it's not a good practice regardless of the language. I'm talking about functions that do the same thing, but do it with small differences based on it's inputs, which should still be considered as one unit.
Examples can be seen in various ranges from NewReader/NewReaderSize above to regexp, NewServer/NewServerWithOptions and fmt.Print* specializations with string etc.
I've found non-overloaded code that accomplish the same thing to be far more verbose needlessly, and as such is counter-intuitive and only more difficult to quickly understand the meaning due to it's argument names littered along with the function name, than well developed overloads that establish what the function does far more effectively. And the exact calls are just a key press away with language assist tools. Practically, I've found that I need to know the precise function far less times, than the task accomplished by the function - or rather - that I'm okay with the extra key press when I need to know more, as opposed the verbosity that it introduces.

Do you mean by this, that it would be better for you if all the regexp matching functions had the same name? I must be misunderstanding you. (?)

Nope. What I suggest lies somewhere in the middle. As suggested in the issue post, where functions that do the same thing (for example finds an Index based on different inputs can be grouped into one). Though, in this specific case, it can also be solved to the same extent by generics, whenever that happens.

C# is not a reference point for good naming, I have to install a 12GiB editor with intellisense to even use the language because its libraries are so convoluted. Users commonly use long Hungarian-ish variable names in short function bodies to compensate for the confusion created by overloading and other wizardry. The net result, in my experience, is not only an unusable mess, but an unreadable one.

@as, well this is not relevant to the issue, however I feel like I should
perhaps question the validity of your experience today, since it's likely
extremely outdated.
No, there's no Hungarian-ish, atleast not in corefx (the std lib) - if you
encountered it likely was a library of questionable design, or had good
reasons like platform compatibility (like go has constants names O_RDWR).
And no, you've not needed VS, or any large IDE ever since the lightweight
language service - which btw is far superior to gocode, at the moment of
this discussion.
So, while I agree C# is not very relevant and I used it only as an example,
I feel you've misused the example by stating points which are not entirely
true (Admittedly they were once upon a time, before Go even existed).
Sent from my Android
On Sep 9, 2017 17:49, "as"<EMAIL_ADDRESS>wrote:

C# is not a reference point for good naming, I have to install a 12GiB
editor with intellisense to even use the language because its libraries are
so convoluted. Users commonly use long Hungarian-ish variable names in
short function bodies to compensate for the confusion created by
overloading and other wizardry. The net result, in my experience, is not
only an unusable mess, but an unreadable one.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/golang/go/issues/21659#issuecomment-328273764, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AAiJMSoPgqCW7V2MgqFzhcrTyb7hZN-Aks5sgoJFgaJpZM4PEPmt
.

Unfortunately, my experience is not outdated. Which is why I am against this proposal. I am all for improving the language, but this proposal hasnt demonstrated what is improved as an end result. You can convince me through practical examples demonstrating so.

@as, but suggesting that you NEED visual studio just to use the language is not true, to say the least. You can easily write in any text editor. And we have lightweight visual studio code with omnisharp or other supported editors. You have to remember your APIs or use docs in the same exact way in either Go or C#.
Not to say that I'm in favor of overloading. I'm not against it but don't really see a big value in it. It can do nice things here and there but, ultimately, brings very little to the table. It brings little value but also brings a little confusion sometimes. At least in C#. C++ is a very different beast.
And, if we look at the C# List as an example. It's nice that we have three BinarySearch all doing the same thing but with different levels of control. But it's not more than that, just nice.

And we have lightweight visual studio code with omnisharp or other supported editors.

IIRC, VSC uses some JS editor...? If is it so, then lightweight does not apply, I'm affraid.

The conversation seems to be taking a detour. Don't know why editors are being discussed.
Just to bring the detour to an end: @cznic https://github.com/OmniSharp/omnisharp-vim - There's as lightweight as you can get with language assist. This is no different than C/C++, or pretty much any language. Arguably more efficient than Go's language assist at the moment, due it being a full fledged Roslyn compiler that providing the assist, rather than parsing the AST, or syntax tree multiple times.

@cznic, lightweight in terms of size. if you don't like VSC for some reason, you can choose other supported editors. Omnisharp supports emacs and vim, for example. C# came a long way since days when you couldn't do anything without visual studio.

if you don't like VSC for some reason

I don't know if I like it because I would never touch it ;-) </offtopic>

@creker

And, if we look at the C# List as an example. It's nice that we have three BinarySearch all doing the same thing but with different levels of control. But it's not more than that, just nice.

Then again, C# has generics. You also use overloading in various places so naturally like new List() and new List(initalSize), or Dictionary, or many collections that follow similar APIs. Imagine if C# had new ListSize() - I, for one, would definitely think its an API that create some numerical value that holds a size.  But that's quite what Go does today. Same goes for API that take in options. It doesn't make the code base unnecessarily verbose.

@prasannavl, it removes verbosity in exchange of clarity sometimes. Let's assume that you remember all API. Without overloading you have functions with different names. Function name tells you exactly, which function it is. With overloading you have to look at the arguments, how many of them, which type they has. If it's more complicated, you have to remember resolution rules to figure out exactly, which function is going to be called.
It's not always the case but it happens even in C# where that kind of stuff is significantly easier than in C++. Also, C# is helped by the fact that pretty much everyone uses intellisense. I, personally, in favor of tools assistance and don't like writing even in Go without them. But still, for me the gain is too little to justify added complexity and confusion even when you have tools to help you.
And if we compare that to generics you mentioned, they have clear value in that they can do something, which you can't do otherwise without writing complex and slow code. Added complexity to the language here is clearly justified. Go even has them in very limited way like slices, maps, channels etc. I would argue that, if generics were to be implemented, overloading would loose even more value.

@creker,

With overloading you have to look at the arguments, how many of them, which type they has. If it's more complicated, you have to remember resolution rules to figure out exactly, which function is going to be called.

I find this interesting. In my personal experience, with Resharper or even with just plain Omni-sharp Intellisense, I've never found this to be a problem, with all the possible functions popped out with docs instantly as I type, and contextually filtered with just the relevant functions as I type more. Even otherwise I've found this easier to figure out "related" functions in the source code, or in the docs, rather than having to scan every one of them.

I, personally, in favor of tools assistance and don't like writing even in Go without them.

Yup, I agree. It's important recognize the value of tooling in language design today. While it's a personal choice for some who want to just pop out a naked editor, I wouldn't want the language to be constrained much because of it. Pseudo IDEs like VSCode pops up pretty much instantly on today's systems with full tooling support.

I would argue that, if generics were to be implemented, overloading would loose even more value.

Honestly, in Go, generics (one would argue it's fundamental to modern languages), thanks to the tease of exploratory proposals, just seem like this promise-land that's just always in the distant future. (https://github.com/golang/go/issues/21659#issuecomment-328266346).
While Generics does help, API's like NewReaderSize will continue to exist in Go without overloading. While generics don't seem to be happening anytime soon in Go, overloading in my opinion is a far far simpler implementation. The implementation I had suggested by nixing the need for dealing with complicated interfaces at all, can be done quite easily. (Admittedly, I have to think about method expressions). And the maintenance cost of that would also not be too much. (I probably might end up in trouble throwing this out there - but I'd say it's probably reasonable to allot a few days to a week at max time-frame by some one familiar with the codebase - Let's just put that in perspective against generics that's stuck in design for 10 years). The real cost practically will be with analysis tooling adaptations, which will take significant time and work to cascade. But that's one time process. When, and if generics comes into Go, there comes two ways to solve some very small class of problems (i.e, some specialized functions that can be made generic, etc), but overloading complements the other cases.
With generic APIs, we also open up a larger class of naming difficulties, and versioning transitions. I'd hate to have a nice generic API, and have to write WithOptions and the likes, and even worse, having to write FindAllGeneric method to complement FindAll because, it cannot be overloaded and deprecated methods and new APIs cannot be provided during the same time. Perhaps, there are clever ways to resolve this particular problem with generics taking on more of it's challenges, but it certainly doesn't make things easier.
In short, the value of overloading isn't shadowed by generics, rather complemented nicely.

@prasannavl

I find this interesting. In my personal experience, with Resharper or even with just plain Omni-sharp Intellisense, I've never found this to be a problem, with all the possible functions popped out with docs instantly as I type, and contextually filtered with just the relevant functions as I type more. Even otherwise I've found this easier to figure out "related" functions in the source code, or in the docs, rather than having to scan every one of them.

Overloading is nice when you're writing code. But when you're reading it you have to deal with the problem I mentioned. The problem becomes even bigger when you have operator overloading. Not only function calls are not obvious now but arithmetic operations also.

Overloading is nice when you're writing code. But when you're reading it you have to deal with the problem I mentioned. The problem becomes even bigger when you have operator overloading. Not only function calls are not obvious now but arithmetic operations also.

Unless someone comes up with some spectacular innovation, I don't think anyone here is even attempting to venture near operator overloading (with notable exceptions like strings, of course). This issue, to my knowledge is only about functions.

@prasannavl
https://github.com/golang/go/issues/21659#issuecomment-328283293 reminds me that overloading is fairly closely tied to function naming, and especially to constructors. When you only get one name to work with for constructor functions — the name of the type itself — you end up needing to work out some way to squeeze lots of different initialization options into just that one name.
Thankfully, Go does not have distinguished “constructors”. The functions we write to return new Go values are just functions, and we can write as many different functions as we want to return a given type: they don't all have to have the same name, so we don't have to work as hard to squeeze everything into that name.

function overloading is bad to read code for me in java and c#.It is difficult to find the implement code as you need to know the type of the function arguments.
I will not use function overloading in java and c#, but others will use it,so it just make write not readable code easier.
Here is my work around with the function overloading need(add arguments after the function has been called by outer caller):
type OpenRequest struct{
   FileName string // need pass this one
   IsReadOnly bool // default false
   IsAppend bool // default false
   Perm FileMode // default 0777
}
func Open(req OpenRequest) (*File,error){
   if req.FileName==""{
     return nil,errors.New(`req.FileName==""`)
   }
   if req.Perm==0{
     req.Perm = 0777
   }
   ...
}
Open(OpenRequest{
   FileName: "a.txt",
})

I just found that you can add almost unlimit number of arguments to this function, and the caller can pass some of arguments, and ignore other one, and the arguments is more readable from caller code.

Here is my work around with the function overloading need(add arguments after the function has been called by outer caller):

Facepalm.

If we are considering function overloading, are we also going to consider pattern matching? In my opinion, they are related: The same concept implemented differently.

If I may be so bold, I don't think that the go authors are "considering"
function overloading. I also enjoy go's simplicity I think as much as
anyone. Personally, I can say that it changed my thinking about programming
in a good way.

Does anyone mentioned that overloading will require additional* name mangling for Go symbols?
With generics on board, this is even more interesting.
(*) As far as I know, there is only package prefix appended to symbol, currently, which is rather trivial.

context adds method repeats to the database/sql API: https://golang.org/pkg/database/sql/
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error)
func (db *DB) Ping() error
func (db *DB) PingContext(ctx context.Context) error
func (db *DB) Prepare(query string) (*Stmt, error)
func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error)
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
func (db *DB) QueryRow(query string, args ...interface{}) *Row
func (db *DB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *Row
...there's more for other types

@pciet, great example! And we're only in v1 of the language. I'm scared of how these APIs will evolve without overloading.

For the context in database/sql case I’m not convinced function overloading is the right pattern to fix repeating APIs. My thought is change *DB to a struct of reference/pointer types and call methods on an sql.DB instead, where the context is an optional field assigned before making these calls to Exec, Ping, Prepare, Query, and QueryRow in which there’s an if DB.context != nil { block with the context handling behavior.

The database/sql case seems to me like an argument for better API versioning rather than for function overloading.

@neild, precisely. And overloading is one of the most helpful ways to achieve that, as mentioned in the initial post.

@neild, precisely. And overloading is one of the most helpful ways to achieve API versioning. (As mentioned in the initial post already)

@prasannavl, as already pointed out, this is not fair solution as it can break existing code that assigns function referring to it by its name (this includes passing the function as an argument).
The whole "versioning" part can be misleading as overloadeding can be backwards-incompatible in unexpected ways (think about C code that calls your Go functions for example of less expected/popular example).
If you know the solutions to those complications or this is an acknowledged risk/tradeoff, please mention it in the first message.

That being said, I can think of a few ways - the obvious one being to pass the signature along - which might seem rather tedious, but the compiler can quite easily infer it - and in cases of ambiguity won't compile. These are "solvable" problems. But API design restrictions imposed by the language itself is not.

I also don't get you point how function overloading helps tooling.

It will get clumsier to "goto definition" of overloaded function because of candidates list.

If there will be much smart inference from the compiler, public API for tools should be provided in order for them to use that information. Otherwise very few tools will adopt it properly.

Tools that rely on the unique property of {package name}+{function name} combinations will break.
And I would not presume that it is very trivial to fix all of those cases. It can be impossible to remedy by go fix.

I have a feeling that you underestimate the associated complexities at the whole picture.
Sorry if I am wrong, but things like "quite easily" or "Complexity level is low to implement it in Go"/"just another function with a suffixed internal name" are confusing.

offtopic
It's also strange that you mention quite unrelated features to adhoc polymorphism while mention C++.
My understanding is that C++ resolutions are hard due to other reasons (templates, namespaces/dependent name lookup are better examples).

But Go doesn't have classes, or similar polymorphism, and isn't as complex as C++.

as already pointed out, this is not fair solution as it can break existing code that assigns function referring to it by its name.
The whole "versioning" part can be misleading as overloadeding can be backwards-incompatible in unexpected ways (think about C code that calls your Go functions for example of less expected/popular example).

Can be backwards-incompatible? Yes.
Should it backwards-incompatible? Not really.
The key here is in how it's implemented. Let's think about the variables are here - It's only the function parameters. So, if we can come up with a way, where the generated function names are tethered to to the function parameters, this can solved nicely. (I do vaguely remember mentioning something on these lines in one of the comments before). That said, I can imagine this being a big problem in a language like C where dynamic linking is extensive. In Go, a majority of the use cases are static and ABI compatibility can also be forgiving (though I don't imply that things should break).
Let take an oversimplified example (oversimplified before this can't work due to other problems yet to be solved discussed in the comments before)
func DoSomething(in string)
func DoSomething(in int32)

And it's internal implementation would look something on the lines of:
func DoSomething__In_String(in string)
func DoSomething__In_Int32(in int32)

This shouldn't break C calling Go, or Go calling Go, or binary compatibility.

I also don't get you point how function overloading helps tooling.

I think it'd be fair to just refer to C# here. The tooling around C# does exactly what I mention, and it's a language with one of the most stellar language services and tooling. (PS: It's handles a lot more complexity that isn't needed in Go, as the language is far more complex).

It will get clumsier to "goto definition" of overloaded function because of candidates list.

Sorry, I really don't see how. Each reference directly is tied to one definition, or it's incorrect code that won't compile.

If there will be much smart inference from the compiler, public API for tools should be provided in order for them to use that information. Otherwise very few tools will adopt it properly.

Possibly. While I'd like to explore the possibility on how the "tax" from this can be reduced, I am certain the best approach in most scenarios is what you mention.

Tools that rely on the unique property of {package name}+{function name} combinations will break.
And I would not presume that it is very trivial to fix all of those cases. It can be impossible to remedy by go fix.

There are no cases that will break existing code. Go 1 tooling will remain compatible with Go 1 code. Hypothetically if Go 2 implements function overloading, the unchanged tooling just won't detect the new function that use overloading, which will of course require updated tooling.

Sorry, I really don't see how. Each reference directly is tied to one definition, or it's incorrect code that won't compile.

Well, maybe that point is not very important for others anyway.
In very-very short form: M-x find-function foo.Bar can't work without additional prompt if multiple foo.Bar exist. This basically boils down to the fact that you need two things instead of one to find the function: it's name and actual arguments (or their types).

@Quasilyte - Ah. Thanks for that. I was thinking of only the goto-definition by pointing at a function use, and navigating to the definition from there.
Thinking of the scenario you mentioned, yes, an additional prompt would be needed, when appropriate. Though most auto-complete I tend to use - VS Code, Gogland, etc have as-you-type fuzzy search anyway that boils it down. So, yes, I suppose it might involve an extra key-press.
I suppose some people value it a great deal while others don't.

@prasannavl, did you answered https://github.com/golang/go/issues/21659#issuecomment-325485157?
Please, consider this case.
It's a technical detail, not subjective or "religious".
I am not a good advisor here, but maybe technical design document may be a better argument than repeating the ones that proven not to be working (not everyone will agree on "API just get's better").
You may browse existing design documents to get inspiration.

There is a backwards-compatible way to introduce adhoc polymorphism into Go without some problems mentioned above though.
Introduce a new keyword that defines overloadable function.
This function can not be assigned assigned unless type elision is possible (see https://github.com/golang/go/issues/12854).
No existing code is affected.
Overloadable functions represented with separate types in go/types (not sure about go/ast).
xfunc add1(x int) int { return x + 1 }
xfunc add1(x float32) float32 { return x + 1 }

f := add1 // Error: can't assign overloadable function
var f1 func(int)int = add1 // OK
var f2 func(float32)float32 = add1 // OK

xfunc is just a placeholder for a better (and new) keyword.

@Quasilyte I'm not @prasannavl but the answer is obvious - compile time error. If type elision doesn't work then compiler should generate an error. Go has var [name] [type] syntax to solve that. No need for new keywords or anything like that. Existing code will continue to compile as long as you don't start adding overloads. And when something breaks it will be trivial to fix by hand. But probably not something that can be fixed by tooling.

@creack you add overloading, but the user code is broken now.
I believe this is not a good thing.
This is why "compile error" is obvious, but suboptimal, in my opinion.

@Quasilyte type inference can be as sophisticated as it can but when there's no other way then compiler should throw an error. The comment that you mentioned is ambiguous without proper context and should not compile. How exactly sophisticate it is should probably be in the proposal document. I agree with you on that.
About breaking client's code, that's definitely something to think about and should be covered extensively in the proposal. Even language like C# has problems with that. But it most cases examples of such breaking are more telling about bad library design rather than problem with overloading. MS adds overloads with every .Net release and doesn't break anything because if you design your API properly then adding an overload is not breaking change.

@bcmills you could still design your API to solve that. If your overloads are ambiguous then it's your problem to make them compatible. Even if reference resolves to different overload client's code is still working.
Say, you had one function
func foo(arg interface{})

Now you add an overload
func foo(io.Reader)

Obviously client's code that passed io.Reader before will now reference the latter overload. It's your problem to retain compatibility between the two even if they're used interchangeably. If your overloads are so incompatible that you can't even solve that then it's obviously API design problem.
Another solution could be on the language level. Forbid referencing overloads without explicitly specifying the exact overload. In other words, f := foo will not compile in any case even if you can infer the type. Also, forbid type conversion between overloads even if arguments are compatible. In the case above, two overloads have different and incompatible types even though you can pass io.Reader as interface{}.

@prasannavl, did you answered #21659 (comment)?
Please, consider this case.
It's a technical detail, not subjective or "religious".

It just doesn't compile. If there's ambiguity you add signatures to compile. (But, this does suffer from the same compatibility issue. More on that below)

@Quasilyte type inference can be as sophisticated as it can but when there's no other way then compiler should throw an error.

@creker, I think @Quasilyte was referring to the part where the function that isn't overloaded, is then overloaded. This could prevent code that compiled before from not compiling. While this isn't really isn't an issue at all when statically linking - it is a significant issue during dynamic linking.
Also since you mentioned C#, just want to point out here, while I think it's fair to compare tooling, I don't think it may be fair comparison to compare on a deeper level. Since C# has IL code in the middle, it provides with more flexibility that Go cannot achieve.

maybe technical design document may be a better argument

@Quasilyte - Yes, I do agree. I think there's significant feedback that has been gained from this thread, to start thinking about a technical document. I hope to find time soon to collect things from this and potential impl possibilities into a document.
PS: While I'm quite obviously advocating FOR overloading, if it HAS to introduce a new keyword, to me personally that would tip the scales, as that defeats the outer language simplicity enough for me to not purse it.
@bcmills - now, coming to the compatibility issue - thinking out loud here, there is one approach to make sure it overloading doesn't break compatibility. But that'll break compatibility with existing Go. It's rather simple, but radical - change the internal repr of every Go function to have it's parameters as a part of the name
Eg:
func Hello(text string)
func Hello1(text string)
func Hello1(name string, text string)

Now the compatibility is an issue only when Hello, and Hello1 follow different methodologies for internal naming. But if you keep it consistent and change the internal representation of both to look like this
func Hello__$CMagic__string()
func Hello1__$CMagic__string()
func Hello1__$CMagic__string_!_string()

This solves compatibility. But introduces slightly more complicated debugging tooling. (Not debugging, but debug tooling). The tooling will then have to actively convert the internal repr to human readable form of Hello1(name, text).

Any approach here will add significant complexity to the spec.  We will need to define something along the lines of the complex C++ rules to choose which overload is desired.  It won't be as complex as C++ but it will be complex.  One of the key reasons that Go code is easy to read is that it is easy to understand what every name refers to.  This proposal will lose that property to some extent.
In code like f := F where F is overloaded you will need to explicitly state the type of f, which is unfortunate.
In code that uses method expressions that refer to an overloaded method, you will have to specify the type of the desired method, but how?  This is a long issue but I don't see any good suggestion above for this problem.

Proposal declined.


Claim Block Bank somehow carrying over to other server(s)

I am normally an Onion player, where as an Omen already have max'd out claim blocks (76k+). Came to Atlas to help with vote party and found a cozy little nook as a new player and decided to claim it. Turns out I have the same amount of claim block bank as I do on my home server.
Expectations:
I only expected to have roughly 500 claim blocks to use as a new player on Atlas.

IGN: JesterFox
Orion

Closing ticket, pre-reset issue.