Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 5:28 AM, Gábor Lehel illiss...@gmail.com wrote: On Sat, Oct 19, 2013 at 10:52 PM, Patrick Walton pwal...@mozilla.comwrote: I think it's unfortunately too late to overhaul the language like this. This will require redesigns of all Rust code in existence. I do like unified function/method call syntax, but I think it can be done in a backwards compatible way. This is up to you and the rest of the Rust team, of course. But in my very humble opinion, it feels shortsighted to impose backwards compatibility constraints at this point. All Rust code in existence is still (hopefully!) a negligibly small fraction of the code that is yet to be written. I know there's a desire to get 1.0 out the door as soon as possible, and I understand it (I want to be using Rust instead of C++, too!), but if Rust is still in use years or decades from now, decisions made now about the design of the language will echo far louder than whether it was released a few months earlier or later. I think it would be unfortunate to start suffering a C++-like fate sooner than absolutely necessary. The Go team has been able to make incompatible language library changes by providing a tool that updates existing programs. Since Go's pretty-printer fully defines the appearance of source code (indenting, line wrapping, etc.), the updater can't mess up such things (and there are no debates about them). That was a general argument, and it only matters if something is considered a good idea on the merits. In this case, it seems we disagree about that: On Sat, Oct 19, 2013 at 11:46 PM, Patrick Walton pwal...@mozilla.comwrote: I was thinking not. The dot operator should still have special name lookup rules: it searches through associated impls and all traits in scope. It cannot call anything that is not attached to an impl. This does make functions and methods somewhat less unified, but it makes methods feel more like OO methods from a scoping POV. I feel the draws of methods are not only that they switch the order of the receiver and action but also that they allow functions associated with a type to be called without explicitly importing their names. Aha. That's exactly the thing I don't like, and thought would be beneficial to change. It's different from everything else for no great reason (is being like OO a great reason?), and carries baggage with warts and thorny issues in it. (Needing special language constructs to write methods; normal `fn`s feel like second-class citizens; can't selectively or rename-import methods; can't write method-syntax functions in a different crate without introducing spurious abstraction boundaries; the whole `impl T { fn(self) }` versus `impl T { fn(self) }` ugliness; traits and generic types in paths raise awkward questions; ...) -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Jerry ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sat, Oct 19, 2013 at 10:52 PM, Patrick Walton pwal...@mozilla.comwrote: I think it's unfortunately too late to overhaul the language like this. This will require redesigns of all Rust code in existence. I do like unified function/method call syntax, but I think it can be done in a backwards compatible way. This is up to you and the rest of the Rust team, of course. But in my very humble opinion, it feels shortsighted to impose backwards compatibility constraints at this point. All Rust code in existence is still (hopefully!) a negligibly small fraction of the code that is yet to be written. I know there's a desire to get 1.0 out the door as soon as possible, and I understand it (I want to be using Rust instead of C++, too!), but if Rust is still in use years or decades from now, decisions made now about the design of the language will echo far louder than whether it was released a few months earlier or later. I think it would be unfortunate to start suffering a C++-like fate sooner than absolutely necessary. That was a general argument, and it only matters if something is considered a good idea on the merits. In this case, it seems we disagree about that: On Sat, Oct 19, 2013 at 11:46 PM, Patrick Walton pwal...@mozilla.comwrote: I was thinking not. The dot operator should still have special name lookup rules: it searches through associated impls and all traits in scope. It cannot call anything that is not attached to an impl. This does make functions and methods somewhat less unified, but it makes methods feel more like OO methods from a scoping POV. I feel the draws of methods are not only that they switch the order of the receiver and action but also that they allow functions associated with a type to be called without explicitly importing their names. Aha. That's exactly the thing I don't like, and thought would be beneficial to change. It's different from everything else for no great reason (is being like OO a great reason?), and carries baggage with warts and thorny issues in it. (Needing special language constructs to write methods; normal `fn`s feel like second-class citizens; can't selectively or rename-import methods; can't write method-syntax functions in a different crate without introducing spurious abstraction boundaries; the whole `impl T { fn(self) }` versus `impl T { fn(self) }` ugliness; traits and generic types in paths raise awkward questions; ...) -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
It's different from everything else because it's a non-overlapping feature :) But yes, I think being like OO is reason enough to do it. If we didn't have that, then you'd have to import every method you call. I think that that would turn off far too many programmers coming from mainstream languages. Almost every mainstream language I can think of that has methods at all does name lookup this way. (The main exception in the OO world would be pure multimethod-based systems, but they aren't mainstream and I personally question whether they can be in part because of this very issue.) Rust was designed to be a multiparadigm language, supporting both functional and OO style, and this feature is an extremely common part of object-oriented programming. If it helps, this feature is not without precedent. The search through associated methods behavior is the same as Go and similar to Objective-C, with its @interface/@implementation divide. The search through traits in scope behavior is similar to Scala and C# extension methods. I don't see the things you mention as warts. They're just consequences of, well, having methods in the OO sense. Nearly all of these warts show up in other object-oriented languages too. Maybe they're warts of object-oriented programming in general and illustrate that OO is a bad idea, but as I mentioned before Rust is designed to support OO. I shouldn't have been so absolute about not changing stuff--we can and will change things--but I don't see having to import every method as a positive change. We discussed it years ago and concluded that it was a non-starter due to the burden it would impose on everyone. Patrick Gábor Lehel illiss...@gmail.com wrote: On Sat, Oct 19, 2013 at 10:52 PM, Patrick Walton pwal...@mozilla.comwrote: I think it's unfortunately too late to overhaul the language like this. This will require redesigns of all Rust code in existence. I do like unified function/method call syntax, but I think it can be done in a backwards compatible way. This is up to you and the rest of the Rust team, of course. But in my very humble opinion, it feels shortsighted to impose backwards compatibility constraints at this point. All Rust code in existence is still (hopefully!) a negligibly small fraction of the code that is yet to be written. I know there's a desire to get 1.0 out the door as soon as possible, and I understand it (I want to be using Rust instead of C++, too!), but if Rust is still in use years or decades from now, decisions made now about the design of the language will echo far louder than whether it was released a few months earlier or later. I think it would be unfortunate to start suffering a C++-like fate sooner than absolutely necessary. That was a general argument, and it only matters if something is considered a good idea on the merits. In this case, it seems we disagree about that: On Sat, Oct 19, 2013 at 11:46 PM, Patrick Walton pwal...@mozilla.comwrote: I was thinking not. The dot operator should still have special name lookup rules: it searches through associated impls and all traits in scope. It cannot call anything that is not attached to an impl. This does make functions and methods somewhat less unified, but it makes methods feel more like OO methods from a scoping POV. I feel the draws of methods are not only that they switch the order of the receiver and action but also that they allow functions associated with a type to be called without explicitly importing their names. Aha. That's exactly the thing I don't like, and thought would be beneficial to change. It's different from everything else for no great reason (is being like OO a great reason?), and carries baggage with warts and thorny issues in it. (Needing special language constructs to write methods; normal `fn`s feel like second-class citizens; can't selectively or rename-import methods; can't write method-syntax functions in a different crate without introducing spurious abstraction boundaries; the whole `impl T { fn(self) }` versus `impl T { fn(self) }` ugliness; traits and generic types in paths raise awkward questions; ...) -- Your ship was destroyed in a monadic eruption. -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
Coming from a functional programming perspective, it would still be very nice indeed to easily pipeline a series of functions (not methods). The current method of requiring defining a new trait (with possibly just one impl!) just to be able to use the `.` syntax means discouraging functional style in favor of OO style. If it is impossible to allow for `foo.bar(baz)` to be the same as `bar(foo, baz)`, without giving up on the OO-like behavior (is it, really?), is there any chance of introducing a whole new operator (such as `|`) to do the trick (as in `foo | bar(baz)`)? See for example Elixir, which provides both a magic `.` OO-ish method dispatch and also a function-ish pipelining `|` operator. On Sun, Oct 20, 2013 at 6:11 PM, Marijn Haverbeke mari...@gmail.com wrote: I want to add that we did initially have a scheme where you have to import every impl you used (not every method), and that this was abandoned because it was burdensome and, in typical situations, completely redundant. Another problem with this proposal seems that it does away with the possibility of explicitly grouping a bunch of methods that make up the implementation of an interface. Implementing interfaces go-style, by just happening to have implemented all the methods that make up the interface, seems inappropriate for a language where interfaces aren't structural. So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 4:56 PM, Patrick Walton pwal...@mozilla.com wrote: I don't see the things you mention as warts. They're just consequences of, well, having methods in the OO sense. Nearly all of these warts show up in other object-oriented languages too. Maybe they're warts of object-oriented programming in general and illustrate that OO is a bad idea, but as I mentioned before Rust is designed to support OO. OO for me was always more tied in with virtual methods than with how methods are scoped. But either way - I think this is basically my view. :) The only part of it I like is dot syntax. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
It seems to me that maybe there are several concepts/changes that are discussed at once, and it would be possible to nitpick. Personally, when I think of unifying calls, I only think of having foo.bar(baz) being strictly equivalent to bar(foo, baz); nothing more than a syntax trick in a way. And thus: + I do not see any reason not to keep a special associated method look-up, though instead it would be tied to the first parameter of the function rather than limited to method-like calls + I do not see any reason not to keep automatically exporting/importing all methods whose first parameter is that of an exported/imported type or trait + I do not see any reason to move from explicit trait implementation to structural and automatic trait implementation (and I would consider it harmful) Thus I am wondering: - if I am missing something fundamental in the proposal by Gabor Lehel (I am not completely accustomed with the Rust terminology/idioms) - if such a simple syntax sugar could make its way into the language -- Matthieu On Sun, Oct 20, 2013 at 7:22 PM, Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 4:56 PM, Patrick Walton pwal...@mozilla.comwrote: I don't see the things you mention as warts. They're just consequences of, well, having methods in the OO sense. Nearly all of these warts show up in other object-oriented languages too. Maybe they're warts of object-oriented programming in general and illustrate that OO is a bad idea, but as I mentioned before Rust is designed to support OO. OO for me was always more tied in with virtual methods than with how methods are scoped. But either way - I think this is basically my view. :) The only part of it I like is dot syntax. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 5:11 PM, Marijn Haverbeke mari...@gmail.com wrote: Another problem with this proposal seems that it does away with the possibility of explicitly grouping a bunch of methods that make up the implementation of an interface. Implementing interfaces go-style, by just happening to have implemented all the methods that make up the interface, seems inappropriate for a language where interfaces aren't structural. No, I completely agree with you here. Traits are awesome and if anyone wants to remove them, I will fight them with forks. The only difference in my proposal is how their methods would be scoped: they would be under the enclosing module, rather than the trait itself being a kind of module. Basically the Haskell model. (Except Haskell's module system is weaker than Rust's.) So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). The main cost would be having to import methods explicitly (or using a glob), as Patrick notes. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 7:31 PM, Gábor Lehel illiss...@gmail.com wrote: So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). The main cost would be having to import methods explicitly (or using a glob), as Patrick notes. Now I'm wondering, though: going with my proposal, if the module structure were just a little bit more fine-grained, I think you could achieve basically the same effect as the current system, if you wanted to. If the convention were to use a module to enclose a type together with its methods (which is already the case in many places), and you did a glob import of that module, you would get what you have now: the type and its methods would all come into scope. Except you could still import selectively, if you wanted to, or do things any other way, if you wanted to, and all of the warts I mentioned would still disappear. In a different crate, you could similarly create a module of extension methods, which could be imported together or selectively, if you wanted to. I don't want to push this too hard if it's past the point of being productive, but I'm now even more convinced that this would be a beneficial change. Types should be types, grouping and scoping should be done with modules (Rust's modules are very capable), and traits should be used for type-based abstraction. I think it would work great. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
Isn't #1 basically what argument-dependent lookup (Koenig lookup) is trying to do in C++? I'm very nervous of going down that road. Patrick Matthieu Monrocq matthieu.monr...@gmail.com wrote: It seems to me that maybe there are several concepts/changes that are discussed at once, and it would be possible to nitpick. Personally, when I think of unifying calls, I only think of having foo.bar(baz) being strictly equivalent to bar(foo, baz); nothing more than a syntax trick in a way. And thus: + I do not see any reason not to keep a special associated method look-up, though instead it would be tied to the first parameter of the function rather than limited to method-like calls + I do not see any reason not to keep automatically exporting/importing all methods whose first parameter is that of an exported/imported type or trait + I do not see any reason to move from explicit trait implementation to structural and automatic trait implementation (and I would consider it harmful) Thus I am wondering: - if I am missing something fundamental in the proposal by Gabor Lehel (I am not completely accustomed with the Rust terminology/idioms) - if such a simple syntax sugar could make its way into the language -- Matthieu On Sun, Oct 20, 2013 at 7:22 PM, Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 4:56 PM, Patrick Walton pwal...@mozilla.comwrote: I don't see the things you mention as warts. They're just consequences of, well, having methods in the OO sense. Nearly all of these warts show up in other object-oriented languages too. Maybe they're warts of object-oriented programming in general and illustrate that OO is a bad idea, but as I mentioned before Rust is designed to support OO. OO for me was always more tied in with virtual methods than with how methods are scoped. But either way - I think this is basically my view. :) The only part of it I like is dot syntax. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
What would happen if two types defined a method called, say, foo, and the importing module glob imported them both? Patrick Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 7:31 PM, Gábor Lehel illiss...@gmail.com wrote: So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). The main cost would be having to import methods explicitly (or using a glob), as Patrick notes. Now I'm wondering, though: going with my proposal, if the module structure were just a little bit more fine-grained, I think you could achieve basically the same effect as the current system, if you wanted to. If the convention were to use a module to enclose a type together with its methods (which is already the case in many places), and you did a glob import of that module, you would get what you have now: the type and its methods would all come into scope. Except you could still import selectively, if you wanted to, or do things any other way, if you wanted to, and all of the warts I mentioned would still disappear. In a different crate, you could similarly create a module of extension methods, which could be imported together or selectively, if you wanted to. I don't want to push this too hard if it's past the point of being productive, but I'm now even more convinced that this would be a beneficial change. Types should be types, grouping and scoping should be done with modules (Rust's modules are very capable), and traits should be used for type-based abstraction. I think it would work great. -- Your ship was destroyed in a monadic eruption. -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 8:01 PM, Patrick Walton pwal...@mozilla.com wrote: What would happen if two types defined a method called, say, foo, and the importing module glob imported them both? Here's the part where I have to say that I'm not intimately familiar with how Rust's existing method lookup works. But I don't see why it would necessarily have to work any differently from the way it does now. If you use dot syntax, it would try to do type-based name resolution (i.e. use the method in scope whose self-type matches), autoborrowing, autoreferencing, and whatever else it currently does to try to get an unambiguous match. If that fails, *then* you would have the option of tweaking your imports, `use`ing the method under a different name, or switching to function syntax and adding an explicit module qualifier (along with explicit borrowing and whatever). -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
But then it seems strange to require that the methods be imported at all, if you're going to do single-dispatch type-based resolution on them anyway. What we could do, perhaps, is add a third source of methods that the dot operator searches: functions in scope. This would allow methods to be attached anywhere to pre-existing types in an ad-hoc basis. I'm a bit nervous about complicating our already-complicated method lookup further, but maybe it makes sense to reduce the number of FooMethods traits people have to write, as well as to accommodate function chaining patterns. Patrick Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 8:01 PM, Patrick Walton pwal...@mozilla.com wrote: What would happen if two types defined a method called, say, foo, and the importing module glob imported them both? Here's the part where I have to say that I'm not intimately familiar with how Rust's existing method lookup works. But I don't see why it would necessarily have to work any differently from the way it does now. If you use dot syntax, it would try to do type-based name resolution (i.e. use the method in scope whose self-type matches), autoborrowing, autoreferencing, and whatever else it currently does to try to get an unambiguous match. If that fails, *then* you would have the option of tweaking your imports, `use`ing the method under a different name, or switching to function syntax and adding an explicit module qualifier (along with explicit borrowing and whatever). -- Your ship was destroyed in a monadic eruption. -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 7:31 PM, Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 5:11 PM, Marijn Haverbeke mari...@gmail.comwrote: Another problem with this proposal seems that it does away with the possibility of explicitly grouping a bunch of methods that make up the implementation of an interface. Implementing interfaces go-style, by just happening to have implemented all the methods that make up the interface, seems inappropriate for a language where interfaces aren't structural. No, I completely agree with you here. Traits are awesome and if anyone wants to remove them, I will fight them with forks. The only difference in my proposal is how their methods would be scoped: they would be under the enclosing module, rather than the trait itself being a kind of module. Basically the Haskell model. (Except Haskell's module system is weaker than Rust's.) Sorry, I think I might have misread the question, which I now believe was not about traits, but about impls. Basically, only anonymous `impl`s would go away. Trait impls would stay. But trait impls wouldn't have an effect on scoping. (Trait methods would be scoped under the module enclosing the trait, `impl`s would only affect for which types there exists an implementation for them. You can' t currently choose whether or not to export or import a trait impl, and you would continue to not be able to do that.) -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 8:16 PM, Patrick Walton pwal...@mozilla.com wrote: But then it seems strange to require that the methods be imported at all, if you're going to do single-dispatch type-based resolution on them anyway. Well, it would do type-based resolution based on the methods which you import :). You would still be the one doing the importing, instead of it happening by magic. You could also /not/ import one or more of them, if you wanted to, which you can currently only do on a per-trait granularity. And the rest of the design would still be much cleaner. (Again, leaving to modules what can be done with modules.) But FWIW, I think this is mostly orthogonal. If you use dot syntax, method lookup happens [somehow]. If it fails, you can do the other things. Maybe method lookup happens with type-based resolution, as it does now. Or maybe it requires that the name itself be unambiguous (which is simpler and dumber), as with functions. That's not really the part I care about. The part I care about is the separation of concerns. What we could do, perhaps, is add a third source of methods that the dot operator searches: functions in scope. This would allow methods to be attached anywhere to pre-existing types in an ad-hoc basis. I'm a bit nervous about complicating our already-complicated method lookup further, but maybe it makes sense to reduce the number of FooMethods traits people have to write, as well as to accommodate function chaining patterns. I still can't speak to the method resolution code :), but I think this would be a positive step. (Requiring the explicit `self` argument would probably make sense, if this were to happen.) -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further
simplification MIME-Version: 1.0 Content-Type: multipart/mixed; boundary7823106168118235853== --===7823106168118235853== Content-Type: multipart/alternative; boundary=4SVSQE8L3ECYN7Z8RACUF07S828YYG --4SVSQE8L3ECYN7Z8RACUF07S828YYG Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable I haven't been completely following this discussion as it's a bit over my head, but if two different types define a method of the same name, it seems to me that there'd be no ambiguity. Java allows function overloading; wouldn't this sort of be similar? From: Patrick Walton Sent: =E2=80=8E10/=E2=80=8E20/=E2=80=8E2013 2:01 PM To: G=C3=A1bor Lehel; Marijn Haverbeke Cc: rust-dev@mozilla.org Subject: Re: [rust-dev] Unified function/method call syntax and further simplification What would happen if two types defined a method called, say, foo, and the= importing module glob imported them both? Patrick G=C3=A1bor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 7:31 PM, G=C3=A1bor Lehel illiss...@gmail.com wrote: So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). The main cost would be having to import methods explicitly (or using a glob), as Patrick notes. Now I'm wondering, though: going with my proposal, if the module structure were just a little bit more fine-grained, I think you could achieve basically the same effect as the current system, if you wanted to. If the convention were to use a module to enclose a type together with its methods (which is already the case in many places), and you did a glob import of that module, you would get what you have now: the type and its methods would all come into scope. Except you could still import selectively, if you wanted to, or do things any other way, if you wanted to, and all of the warts I mentioned would still disappear. In a different crate, you could similarly create a module of extension methods, which could be imported together or selectively, if you wanted to. I don't want to push this too hard if it's past the point of being productive, but I'm now even more convinced that this would be a beneficial change. Types should be types, grouping and scoping should be done with modules (Rust's modules are very capable), and traits should be used for type-based abstraction. I think it would work great. --=20 Your ship was destroyed in a monadic eruption. --=20 Sent from my Android phone with K-9 Mail. Please excuse my brevity. --4SVSQE8L3ECYN7Z8RACUF07S828YYG Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable HTMLHEAD META content=3Dtext/html; charset=3Dutf-8 http-equiv=3DContent-Type/HE= AD BODY DIV DIV style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serifI haven't b= een completely following this discussion as it's a bit over my head, but if= two different types define a method of the same name, it seems to me that = there'd be no ambiguity. Java allows function overloading; wouldn't this so= rt of be similar?/DIV/DIV DIV dir=3Dltr HR SPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serif; FONT-WEIGH= T: boldFrom: /SPANSPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,= sans-serifA href=3Dmailto:pwal...@mozilla.com;Patrick Walton/A/SPAN= BRSPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serif; FONT-= WEIGHT: boldSent: /SPANSPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Cal= ibri,sans-serif=E2=80=8E10/=E2=80=8E20/=E2=80=8E2013 2:01 PM/SPANBRS= PAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serif; FONT-WEIGHT:= boldTo: /SPANSPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans= -serifA href=3Dmailto:illiss...@gmail.com;G=C3=A1bor Lehel/A; A hre= f=3Dmailto:mari...@gmail.com;Marijn Haverbeke/A/SPANBRSPAN style= =3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serif; FONT-WEIGHT: boldCc= : /SPANSPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serif= A href=3Dmailto:rust-dev@mozilla.org;rust-dev@mozilla.org/A/SPANBR= SPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibri,sans-serif; FONT-WEIGHT= : boldSubject: /SPANSPAN style=3DFONT-SIZE: 11pt; FONT-FAMILY: Calibr= i,sans-serifRe: [rust-dev] Unified function/method call syntax and furthe= r simplification/SPANBRBR/DIV/BODY/HTMLhtmlhead/headbody= What would happen if two types defined a method called, say, quot;fooquo= t;, and the importing module glob imported them both?br br Patrickbrbrdiv class=3Dgmail_quotequot;G=C3=A1bor Lehelquot; lt;= illiss...@gmail.comgt; wrote:blockquote class=3Dgmail_quote style=3Dma= rgin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding= -left: 1ex; div dir=3Dltrdiv class=3Dgmail_extradiv class=3Dgmail_quoteOn S= un, Oct 20, 2013 at 7:31 PM, G=C3=A1bor Lehel span dir=3Dltrlt;a href= =3Dmailto:illiss...@gmail.com; target=3D_blankilliss
Re: [rust-dev] Unified function/method call syntax and further simplification
I guess I just don't see the value in requiring imports of names when there can be no ambiguity and they're defined in one place (the impl of the type, defined in the same place as the type itself). One person's magic is another person's smart compiler. I'm not convinced that this is solving a real problem. The search all traits in scope behavior strikes me as far more magical than this. Doing type-based lookup without imports, if the names all had to be defined in one place, seems like a bog-standard language feature to me. It's probably easier to list languages that *don't* have this feature in some form than to list languages that do, honestly... Patrick Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 8:16 PM, Patrick Walton pwal...@mozilla.com wrote: But then it seems strange to require that the methods be imported at all, if you're going to do single-dispatch type-based resolution on them anyway. Well, it would do type-based resolution based on the methods which you import :). You would still be the one doing the importing, instead of it happening by magic. You could also /not/ import one or more of them, if you wanted to, which you can currently only do on a per-trait granularity. And the rest of the design would still be much cleaner. (Again, leaving to modules what can be done with modules.) But FWIW, I think this is mostly orthogonal. If you use dot syntax, method lookup happens [somehow]. If it fails, you can do the other things. Maybe method lookup happens with type-based resolution, as it does now. Or maybe it requires that the name itself be unambiguous (which is simpler and dumber), as with functions. That's not really the part I care about. The part I care about is the separation of concerns. What we could do, perhaps, is add a third source of methods that the dot operator searches: functions in scope. This would allow methods to be attached anywhere to pre-existing types in an ad-hoc basis. I'm a bit nervous about complicating our already-complicated method lookup further, but maybe it makes sense to reduce the number of FooMethods traits people have to write, as well as to accommodate function chaining patterns. I still can't speak to the method resolution code :), but I think this would be a positive step. (Requiring the explicit `self` argument would probably make sense, if this were to happen.) -- Your ship was destroyed in a monadic eruption. -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sun, Oct 20, 2013 at 9:38 PM, Patrick Walton pwal...@mozilla.com wrote: I guess I just don't see the value in requiring imports of names when there can be no ambiguity and they're defined in one place (the impl of the type, defined in the same place as the type itself). One person's magic is another person's smart compiler. A big part of the motivation would be to allow declaring methods anywhere, without using traits, and then they're defined in one place stops being true. For that to be workable you need to have control over imports. (Luckily with top-level functions, you already do.) I'm not convinced that this is solving a real problem. It's not solving a real problem so much as simplifying the whole thing. Despite having used the word, my beef with the current system is not so much that it's magical. It's that it's completely unnecessary. With nothing more than a simple syntax rule and the existing module system, you can recover all of the expressive power of the current system, and more. Compare: -- Design 1 -- - You can declare functions using `fn`. - Functions in the current scope can be called using dot syntax with the first argument as the receiver. (Optionally: only if the first argument is named `self`.) - The module system can be used to group types, functions, and other items, import them together, selectively, or under different names, and resolve ambiguities between them. -- Design 2 -- - Anonymous `impl` blocks can be used to associate methods with a type. - Methods are scoped under and imported together with their type or trait. - Because of this, an anonymous `impl` can only be declared in the same module as its type. - If you want to declare a method somewhere else, declare an auxiliary trait and implement it for that type. - For a method to be called with dot syntax, it has to be declared using special `self`, `self`, `~self`, (or so forth) syntax, which only works with the built-in pointer types. Such a method can't be called with function syntax. - If you want a self-type other than one of the built-in pointers, write an `impl` specifically for that type. - Types and traits are like modules in some ways (you can use them in a path), but not others (you can't `use` from them). - There are special rules and/or syntax for dealing with traits, generic types, and optionally their type arguments in paths. - In addition to methods, you can also declare top-level functions with `fn`. These can only be called with function syntax. - The module system can be used to group, import, rename, and resolve ambiguities between types, functions, and other items except for methods. Which one feels like the tighter design? With some extensions (methods can be called with function syntax, in-scope functions are also considered during method lookup), Design 2 could close the expressiveness gap versus Design 1. But the simplicity gap would remain. The search all traits in scope behavior strikes me as far more magical than this. All of that said, maybe I'm insufficiently worked up about the method lookup rules. :) Searching trait impls does sound a little bit scary. What about, as a less scary in-between solution, while not throwing the baby out with the bathwater, attempting to unify the type of the receiver with the types of the first (`self`) arguments of the functions of the given name in the current scope, but *not* looking at trait impls? And if there's a unique match (modulo autoborrowing and such) it's selected, otherwise an error is reported. Whether appropriate trait impls exist would be checked after a method is selected. This means that if you have a trait method or function in scope which is generic in its self-type, and any other function which also matches the type of the receiver, it would lead to ambiguity. But as (in my proposal) you would no longer have to use traits to implement extension methods, this would hopefully be a less common occurrence. Again though, I think this can and should be considered as a separate matter. It could be done inside the current system, I think, if you wanted to. The differences in the context of my proposal are the aforementioned not having to use traits for extension methods, and that you would have more ways to resolve an ambiguity. It's probably easier to list languages that *don't* have this feature in some form than to list languages that do, honestly... That's because all of the mainstream languages follow misguided OO ideas, and most of the others copy them. :-) -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
Maximum conceptual simplicity has never been a design goal of Rust. If we wanted maximum simplicity we would just eliminate the dot operator entirely and use explicit existential types for trait objects like Haskell. I know that the dot operator is additional unnecessary complexity. No argument there. The thing is that the lookup rules are complexity I think we should buy into because of the convenience and familiarity we get from them. We tried explicit implementation importing, as well as having no dot operator at all, in early versions of Rust. That language was a lot less convenient and limited than Rust of today. The dot operator is there to allow object-oriented programming, including type-based method lookup. If you find OO distasteful, then you should be able to avoid use of the dot operator and still program Rust without loss of functionality (well, first-class trait objects excepted). That is what I had in mind with UMCS. As for some of the specifics in your list, I'd like to fix them. For example, I was going to bring up allowing custom smart pointer self types, as well as allowing use from impls, at a meeting soon. In general I have been thinking that type implementations and traits should be considered modules and should admit everything that can appear in a module. Patrick Gábor Lehel illiss...@gmail.com wrote: On Sun, Oct 20, 2013 at 9:38 PM, Patrick Walton pwal...@mozilla.com wrote: I guess I just don't see the value in requiring imports of names when there can be no ambiguity and they're defined in one place (the impl of the type, defined in the same place as the type itself). One person's magic is another person's smart compiler. A big part of the motivation would be to allow declaring methods anywhere, without using traits, and then they're defined in one place stops being true. For that to be workable you need to have control over imports. (Luckily with top-level functions, you already do.) I'm not convinced that this is solving a real problem. It's not solving a real problem so much as simplifying the whole thing. Despite having used the word, my beef with the current system is not so much that it's magical. It's that it's completely unnecessary. With nothing more than a simple syntax rule and the existing module system, you can recover all of the expressive power of the current system, and more. Compare: -- Design 1 -- - You can declare functions using `fn`. - Functions in the current scope can be called using dot syntax with the first argument as the receiver. (Optionally: only if the first argument is named `self`.) - The module system can be used to group types, functions, and other items, import them together, selectively, or under different names, and resolve ambiguities between them. -- Design 2 -- - Anonymous `impl` blocks can be used to associate methods with a type. - Methods are scoped under and imported together with their type or trait. - Because of this, an anonymous `impl` can only be declared in the same module as its type. - If you want to declare a method somewhere else, declare an auxiliary trait and implement it for that type. - For a method to be called with dot syntax, it has to be declared using special `self`, `self`, `~self`, (or so forth) syntax, which only works with the built-in pointer types. Such a method can't be called with function syntax. - If you want a self-type other than one of the built-in pointers, write an `impl` specifically for that type. - Types and traits are like modules in some ways (you can use them in a path), but not others (you can't `use` from them). - There are special rules and/or syntax for dealing with traits, generic types, and optionally their type arguments in paths. - In addition to methods, you can also declare top-level functions with `fn`. These can only be called with function syntax. - The module system can be used to group, import, rename, and resolve ambiguities between types, functions, and other items except for methods. Which one feels like the tighter design? With some extensions (methods can be called with function syntax, in-scope functions are also considered during method lookup), Design 2 could close the expressiveness gap versus Design 1. But the simplicity gap would remain. The search all traits in scope behavior strikes me as far more magical than this. All of that said, maybe I'm insufficiently worked up about the method lookup rules. :) Searching trait impls does sound a little bit scary. What about, as a less scary in-between solution, while not throwing the baby out with the bathwater, attempting to unify the type of the receiver with the types of the first (`self`) arguments of the functions of the given name in the current scope, but *not* looking at trait impls? And if there's a unique match (modulo autoborrowing and such) it's selected, otherwise an error is reported. Whether appropriate trait impls exist would be checked after a method
Re: [rust-dev] Unified function/method call syntax and further simplification
Interesting idea; in that case, one could string together any series of functions - basically, `.` would become the equivalent of `|` (or whatever other name you want to call it). That is, instead of writing `baz(bar(foo(x), y), z)` one could write `foo(x).bar(y).baz(z)`. This would make it easier to write things in functional style, using the same syntax as the object style. It could be viewed as the natural complement for the `do` keyword, which adds a last block parameter to the end of the function. I'm less certain about giving up `impl Foo { ... }`, though - that is useful for logically grouping, documenting and accessing functions (as in `Foo::foo(...)`). But it seems we don't have to give it up, just make it optional? On Sat, Oct 19, 2013 at 3:47 PM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: I see no reason for the restriction of self. Why not simply say that any function can be called with first_arg.func(...) style ? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sat, Oct 19, 2013 at 4:08 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: I'm less certain about giving up `impl Foo { ... }`, though - that is useful for logically grouping, documenting and accessing functions (as in `Foo::foo(...)`). But it seems we don't have to give it up, just make it optional? Interesting point. I think this argues in favor of removing anonymous `impl`s, even as sugar. I was focused on normal (selfish) methods in my previous letter, rather than static (selfless) ones. You could still achieve much the same effect, if you wanted to, by writing: struct Foo { .. } fn get_thing(self: Foo) - Bar { .. } // for `some_foo.get_thing()` syntax mod Foo { fn new() - Foo { .. } // for `Foo::new()` syntax } Rust already allows this trickery: the type and module are imported together when you write `use some_mod::Foo`. Keeping this seems fine, and making it more explicit (relative to `impl`) seems like a good thing. What you lose is that in the case of a generic type, you would have to write the generic-bits for each function, which is the more typing disadvantage from earlier. I think losing the `impl` sugar is a small price to pay for the simplification of the language. Modules would be modules and types would be types. Append to the advantages list: - The complexity related to (possibly-generic) types in paths would go away On Sat, Oct 19, 2013 at 3:47 PM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: I see no reason for the restriction of self. Why not simply say that any function can be called with first_arg.func(...) style ? Yeah, as I mentioned in the last bullet of the previous letter, you could do this. I don't think it makes much difference either way and don't have a strong opinion. In favor of explicit `self` is that it's, well, explicit: you can and should call this using method syntax. I can imagine there might be function signatures where using method syntax wouldn't make sense (though you might say, then don't use it, and I would be inclined to agree). A non-method function (one without a `self` arg) also wouldn't cause ambiguity if it were in scope at the same time as you were calling another method with the same name. In favor of always allowing method syntax on the first argument is that you could destructure it in the definition, e.g. `fn area((x, y): (int, int)) - int { x * y }`, and still call the function using method syntax. They're all pretty minor. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
I think it's unfortunately too late to overhaul the language like this. This will require redesigns of all Rust code in existence. I do like unified function/method call syntax, but I think it can be done in a backwards compatible way. Patrick Gábor Lehel illiss...@gmail.com wrote: On Sat, Oct 19, 2013 at 4:08 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: I'm less certain about giving up `impl Foo { ... }`, though - that is useful for logically grouping, documenting and accessing functions (as in `Foo::foo(...)`). But it seems we don't have to give it up, just make it optional? Interesting point. I think this argues in favor of removing anonymous `impl`s, even as sugar. I was focused on normal (selfish) methods in my previous letter, rather than static (selfless) ones. You could still achieve much the same effect, if you wanted to, by writing: struct Foo { .. } fn get_thing(self: Foo) - Bar { .. } // for `some_foo.get_thing()` syntax mod Foo { fn new() - Foo { .. } // for `Foo::new()` syntax } Rust already allows this trickery: the type and module are imported together when you write `use some_mod::Foo`. Keeping this seems fine, and making it more explicit (relative to `impl`) seems like a good thing. What you lose is that in the case of a generic type, you would have to write the generic-bits for each function, which is the more typing disadvantage from earlier. I think losing the `impl` sugar is a small price to pay for the simplification of the language. Modules would be modules and types would be types. Append to the advantages list: - The complexity related to (possibly-generic) types in paths would go away On Sat, Oct 19, 2013 at 3:47 PM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: I see no reason for the restriction of self. Why not simply say that any function can be called with first_arg.func(...) style ? Yeah, as I mentioned in the last bullet of the previous letter, you could do this. I don't think it makes much difference either way and don't have a strong opinion. In favor of explicit `self` is that it's, well, explicit: you can and should call this using method syntax. I can imagine there might be function signatures where using method syntax wouldn't make sense (though you might say, then don't use it, and I would be inclined to agree). A non-method function (one without a `self` arg) also wouldn't cause ambiguity if it were in scope at the same time as you were calling another method with the same name. In favor of always allowing method syntax on the first argument is that you could destructure it in the definition, e.g. `fn area((x, y): (int, int)) - int { x * y }`, and still call the function using method syntax. They're all pretty minor. -- Your ship was destroyed in a monadic eruption. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sat, Oct 19, 2013 at 1:52 PM, Patrick Walton pwal...@mozilla.com wrote: I think it's unfortunately too late to overhaul the language like this. This will require redesigns of all Rust code in existence. I do like unified function/method call syntax, but I think it can be done in a backwards compatible way. What do you have in mind at the moment? Implementing UFCS while still keeping the `impl` syntax around for structs? What about for primitive types, e.g. would `fn double(a: int) - { 2*a }` be callable as `2.double()`, without breaking backward compatibility? Thanks -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
This is meant as a followup to an earlier thread[1] on the subject and the related ticket[2]. [1]: http://thread.gmane.org/gmane.comp.lang.rust.devel/2622/ [2]: https://github.com/mozilla/rust/issues/6974 The idea in those earlier discussions is that methods could also be called using function syntax, supplying `self` as the first argument, so instead of `self_arg.method(arg)`, you could write `method(self_arg, arg)`. I'm wondering if this could be taken a couple steps further to simplify the whole story regarding functions, methods, traits, and impls. The idea is that the distiction between functions and methods would be erased almost completely, and methods (now being just functions) would be imported explicitly. It would involve the following pieces: - If the first argument of a top-level `fn` is named `self`, it can be called using method syntax. So if you have `fn foo(self: MyType, n: int) { .. }` at the top level, you can write `object_of_my_type.foo(123)`. You can also still call it using function syntax: `foo(object_of_my_type, 123)`. I see no reason for the restriction of self. Why not simply say that any function can be called with first_arg.func(...) style ? D has that rule (which they call UFCS), and I find it confusing sometimes. When a function is declared with function syntax and it makes sense or feels right that it should be a function, my mind is not expecting to see method syntax and I may have trouble figuring out later what an apparent method call refers to, even if I've seen the function declaration. Mind you it is worse in D than Rust, because in D, function declarations can be hidden inside what they call eponymous templates, which has stumped me in the past. In any case, wouldn't it help narrow down searches if you could search for fn foo(self instead of only fn foo? (again though, Rust is not as bad for searching as the C-family languages that have no fn keyword.) In C# it's nice that I can find all the so-called extension methods by searching for (this . ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Sat, Oct 19, 2013 at 4:35 PM, David Piepgrass qwertie...@gmail.comwrote: In C# it's nice that I can find all the so-called extension methods by searching for (this . Aren't `impl`s in Rust somewhat similar to extension methods in C#? For instance: trait Doubler { fn double(self) - Self; } impl Doubler for int { fn double(self) - int { *self * 2 } } Then you can call 5.double(). -- Ziad ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
On Saturday, October 19, 2013, Ziad Hatahet wrote: On Sat, Oct 19, 2013 at 4:35 PM, David Piepgrass qwertie...@gmail.comjavascript:_e({}, 'cvml', 'qwertie...@gmail.com'); wrote: In C# it's nice that I can find all the so-called extension methods by searching for (this . Aren't `impl`s in Rust somewhat similar to extension methods in C#? Loosely, if you ignore that each impl overloads an abstract interface (trait) over the Self type, and that you can constrain a type parameter based on whether there's an overload of a certain abstract interface for it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev