payload: {"action":"closed","issue":{"url":"https://api.github.com/repos/odin-lang/Odin/issues/372","repository_url":"https://api.github.com/repos/odin-lang/Odin","labels_url":"https://api.github.com/repos/odin-lang/Odin/issues/372/labels{/name}","comments_url":"https://api.github.com/repos/odin-lang/Odin/issues/372/comments","events_url":"https://api.github.com/repos/odin-lang/Odin/issues/372/events","html_url":"https://github.com/odin-lang/Odin/issues/372","id":441075999,"node_id":"MDU6SXNzdWU0NDEwNzU5OTk=","number":372,"title":"[proposal] #overload directive for procedure overloading","user":{"login":"hasenj","id":31078,"node_id":"MDQ6VXNlcjMxMDc4","avatar_url":"https://avatars0.githubusercontent.com/u/31078?v=4","gravatar_id":"","url":"https://api.github.com/users/hasenj","html_url":"https://github.com/hasenj","followers_url":"https://api.github.com/users/hasenj/followers","following_url":"https://api.github.com/users/hasenj/following{/other_user}","gists_url":"https://api.github.com/users/hasenj/gists{/gist_id}","starred_url":"https://api.github.com/users/hasenj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hasenj/subscriptions","organizations_url":"https://api.github.com/users/hasenj/orgs","repos_url":"https://api.github.com/users/hasenj/repos","events_url":"https://api.github.com/users/hasenj/events{/privacy}","received_events_url":"https://api.github.com/users/hasenj/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2019-05-07T07:14:43Z","updated_at":"2019-05-15T20:30:39Z","closed_at":"2019-05-15T20:30:39Z","author_association":"NONE","body":"**Is your feature request related to a problem? Please describe.**\r\nMost languages provide only one way for extending functionality: dynamic dispatch via virtual functions.\r\n\r\nIn Go, it's `interface`, in Swift, it's `protocol`.\r\n\r\nRust provides something called `Traits`, and while I'm not aware of its details, it seems a bit complicated.\r\n\r\nI think it would be nice if Odin had something that could do something similar to what interfaces in Go are used for, with the condition that:\r\n\r\n1) It should not incur _any_ runtime overhead\r\n\r\n2) Should not introduce a new type of procedures into the language (e.g. no 'method')\r\n\r\nOdin has parametrically polymorphic (parapoly) procedures, which I think can be a good starting point.\r\n\r\nIf Odin would allow overloading procedures defined by another package, then it would probably satisfy most use cases for virtual functions, without having virtual functions.\r\n\r\n**Describe the solution you'd like**\r\n\r\nI want to define a parapoly procedure that calls another 'procedure' which might not be parapoly, but can be overloaded for many types.\r\n\r\nTake this example. The code might be broken, but bear with me and assume the logic is correct:\r\n\r\n```odin\r\npackage byte_readers;\r\n\r\n// based on https://golang.org/src/bytes/buffer.go?s=6885:6944#L192\r\n\r\nMIN_READ :: 512\r\n\r\nread_all_bytes_from_reader(reader: $T, output: ^[dynamic]byte) -> (int, os.Errno) {\r\n    total_read := 0\r\n    for {\r\n        new_start := grow_buffer(output, MIN_READ); // definition left as exercise; grows capacity by length + MIN_READ without altering length\r\n        read_count, err := reader_read(reader, output[new_start:]); // assumes procedure `reader_read(T, []byte) -> os.Errno` is defined for T\r\n        if read_count > 0 do total_read += read_count;\r\n        if is_eof(err) do return total_read, 0;\r\n        if err do return total_read, err;\r\n        output = output[:new_start+read_count];\r\n    }\r\n}\r\n\r\n```\r\n\r\nThis parapoly procedure would only work if `reader_read` has an overload for type T.\r\n\r\nWithin the package that defines this procedure, this is not a problem: I can define several `reader_read_xxx` procedures and then define the overloads explicitly in one go:\r\n\r\n    reader_read :: proc{reader_read_xxx1, reader_read_xxx2, reader_read_xxx3}\r\n\r\nThis is however not great for external users of this package.\r\n\r\nI would like it if it was possible to provide an overload for a procedure even if it was defined in a different package.\r\n\r\nSay I have my custom type. Again the code is probably broken, but just assume the logic works:\r\n\r\n```odin\r\n\r\npackage virtual_fs;\r\n\r\nVirtual_File :: struct {\r\n    content: []byte,\r\n    cursor: int,\r\n}\r\n\r\nread_from_file(file: ^Virtual_File, output: []byte) -> (int, os.Errno) {\r\n    last := file.cursor + len(output)\r\n    err := 0\r\n    if file.cursor + len(output) >= len(file.content) {\r\n        last = len(file.content);\r\n        err = EOF;\r\n    }\r\n    read_count := last - file.cursor;\r\n    copy(file.content[file.cursor:last], output);\r\n    return read_count, err;\r\n}\r\n```\r\n\r\nI want to be able to say this:\r\n\r\n    #overload byte_readers.read_from with virtual_fs.read_from_file\r\n\r\nThis should fail to compile if there's already another overload with the same parameters.\r\n\r\n**Additional context**\r\n\r\nI tried to adhere to keeping procedure overloading explicit and keeping the language simple.\r\n\r\nAlthough I suspect this might be complicated to implement in the compiler.\r\n\r\nOne negative point it might introduce is packages are no longer self-contained: a package can be 'extended' in a sense by another package that imports it, but in a sense, this is already the case. Because you a procedure that accepts polymorphic parameters can also accept types that come from other packages that it itself isn't aware of."}}
other: {"actor":{"display_login":"gingerBill"}}