From pwalton at mozilla.com Wed Aug 1 18:53:35 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Wed, 01 Aug 2012 18:53:35 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons Message-ID: <5019DD9F.7060809@mozilla.com> Hi everyone, I have a patch that allows trailing semicolons in most cases in Rust code. This means that code like this will compile: fn f(x: int) -> int { x + 3; } At the moment, this does not compile. You must write: fn f(x: int) -> int { x + 3 } For the most part, it does not alter the current rules as to whether return values can be ignored. Return values can continue to be ignored in almost all contexts; I didn't have to change any code in the compiler or standard libraries. Thus this is in practice a backwards-compatible change intended to eliminate a good deal of toe-stubbing. There is one subtle source of backwards-incompatibility though: You may not drop the return value in sugared lambda expressions if you assign them to a variable (i.e. if the type isn't immediately known). Thus this does not do what it did before: // This return value is intended to be ignored. fn f() -> int { error!("Hi!"); 3 } fn main() { let g = || { f(); }; error!("%?", g()); // prints 3, not () } I personally feel that this particular gotcha is a small price to pay for eliminating a frequent source of newcomer frustration, but it is worth pointing out. Note that this does not apply for downward block closures; if you're passing a lambda to a function, the return value of the lambda can be safely ignored as before if the lambda is intended to return unit. Another downside is that some complexity is added to typechecking; the typechecker is now aware of statement positions (which are expected to return unit) and expression positions (which aren't). Note that Scala seems to have already implemented a rule similar to this, so it isn't without precedent; it also affects only how HM inference is invoked, not the nature of unification itself. I'd like to get feedback as to whether this is a good idea. Comments welcome! Patrick From gwillen at nerdnet.org Wed Aug 1 19:03:01 2012 From: gwillen at nerdnet.org (Glenn Willen) Date: Wed, 1 Aug 2012 19:03:01 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <5019DD9F.7060809@mozilla.com> References: <5019DD9F.7060809@mozilla.com> Message-ID: I for one liked the clear and unambiguous rule: semicolon discards value, no-semicolon returns value. The idea of allowing uniform semicolon use is appealing, but it does seem to add complexity and mysteriousness. FWIW, since I'm not exactly a major player in the Rustiverse currently. :-) gwillen On Aug 1, 2012, at 6:53 PM, Patrick Walton wrote: > Hi everyone, > > I have a patch that allows trailing semicolons in most cases in Rust code. This means that code like this will compile: > > fn f(x: int) -> int { > x + 3; > } > > At the moment, this does not compile. You must write: > > fn f(x: int) -> int { > x + 3 > } > > For the most part, it does not alter the current rules as to whether return values can be ignored. Return values can continue to be ignored in almost all contexts; I didn't have to change any code in the compiler or standard libraries. Thus this is in practice a backwards-compatible change intended to eliminate a good deal of toe-stubbing. > > There is one subtle source of backwards-incompatibility though: You may not drop the return value in sugared lambda expressions if you assign them to a variable (i.e. if the type isn't immediately known). Thus this does not do what it did before: > > // This return value is intended to be ignored. > fn f() -> int { > error!("Hi!"); > 3 > } > fn main() { > let g = || { f(); }; > error!("%?", g()); // prints 3, not () > } > > I personally feel that this particular gotcha is a small price to pay for eliminating a frequent source of newcomer frustration, but it is worth pointing out. Note that this does not apply for downward block closures; if you're passing a lambda to a function, the return value of the lambda can be safely ignored as before if the lambda is intended to return unit. > > Another downside is that some complexity is added to typechecking; the typechecker is now aware of statement positions (which are expected to return unit) and expression positions (which aren't). Note that Scala seems to have already implemented a rule similar to this, so it isn't without precedent; it also affects only how HM inference is invoked, not the nature of unification itself. > > I'd like to get feedback as to whether this is a good idea. Comments welcome! > > Patrick > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > > !DSPAM:5019d823101041336712104! > -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 243 bytes Desc: This is a digitally signed message part URL: From hatahet at gmail.com Wed Aug 1 19:10:53 2012 From: hatahet at gmail.com (Ziad Hatahet) Date: Wed, 1 Aug 2012 19:10:53 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> Message-ID: I agree with Glenn. I personally did not have an issue while trying to pick up Rust to figure out the implicit return with the lack of the semi-colon. In fact, I was able to pick up this pattern just by browsing some Rust code and not looking at the manual or tutorial pages. :) I also think that it is easier to parse visually the way it is now. -- Ziad On Wed, Aug 1, 2012 at 7:03 PM, Glenn Willen wrote: > I for one liked the clear and unambiguous rule: semicolon discards value, > no-semicolon returns value. > > The idea of allowing uniform semicolon use is appealing, but it does seem > to add complexity and mysteriousness. > > FWIW, since I'm not exactly a major player in the Rustiverse currently. :-) > > gwillen > > On Aug 1, 2012, at 6:53 PM, Patrick Walton wrote: > > > Hi everyone, > > > > I have a patch that allows trailing semicolons in most cases in Rust > code. This means that code like this will compile: > > > > fn f(x: int) -> int { > > x + 3; > > } > > > > At the moment, this does not compile. You must write: > > > > fn f(x: int) -> int { > > x + 3 > > } > > > > For the most part, it does not alter the current rules as to whether > return values can be ignored. Return values can continue to be ignored in > almost all contexts; I didn't have to change any code in the compiler or > standard libraries. Thus this is in practice a backwards-compatible change > intended to eliminate a good deal of toe-stubbing. > > > > There is one subtle source of backwards-incompatibility though: You may > not drop the return value in sugared lambda expressions if you assign them > to a variable (i.e. if the type isn't immediately known). Thus this does > not do what it did before: > > > > // This return value is intended to be ignored. > > fn f() -> int { > > error!("Hi!"); > > 3 > > } > > fn main() { > > let g = || { f(); }; > > error!("%?", g()); // prints 3, not () > > } > > > > I personally feel that this particular gotcha is a small price to pay > for eliminating a frequent source of newcomer frustration, but it is worth > pointing out. Note that this does not apply for downward block closures; if > you're passing a lambda to a function, the return value of the lambda can > be safely ignored as before if the lambda is intended to return unit. > > > > Another downside is that some complexity is added to typechecking; the > typechecker is now aware of statement positions (which are expected to > return unit) and expression positions (which aren't). Note that Scala seems > to have already implemented a rule similar to this, so it isn't without > precedent; it also affects only how HM inference is invoked, not the nature > of unification itself. > > > > I'd like to get feedback as to whether this is a good idea. Comments > welcome! > > > > Patrick > > _______________________________________________ > > Rust-dev mailing list > > Rust-dev at mozilla.org > > https://mail.mozilla.org/listinfo/rust-dev > > > > > > !DSPAM:5019d823101041336712104! > > > > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pwalton at mozilla.com Wed Aug 1 20:47:32 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Wed, 01 Aug 2012 20:47:32 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> Message-ID: <5019F854.2050605@mozilla.com> On 08/01/2012 07:03 PM, Glenn Willen wrote: > I for one liked the clear and unambiguous rule: semicolon discards > value, no-semicolon returns value. > > The idea of allowing uniform semicolon use is appealing, but it does > seem to add complexity and mysteriousness. Actually, the only parser change was to throw away semicolons before the end of the block. To be more concrete, the rules are: 1. The last expression is the value of the block, regardless of whether there's a semicolon after it. (This seems like a simplification to me.) 2. "Statement positions" are defined as the position of any expression immediately before a ";" (if that ";" has anything after it) and the last value of a function declared to return unit. Given that: 3. The type of an expression in a statement position is ignored. 4. The types of the arms of a pattern match and the bodies of if/else statements in statement position are ignored. I think the rules are pretty simple, but I'm biased :) Also, the pretty printer will never write a semicolon after an expression in trailing position, so if you like the visual consistency the pretty printer will preserve it for you. (Somewhat surprised at the response here, actually; this thread from 8 months ago [1] had near-unanimity the other way!) Patrick [1]: https://mail.mozilla.org/pipermail/rust-dev/2012-January/001263.html From ben.striegel at gmail.com Thu Aug 2 07:22:08 2012 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Thu, 2 Aug 2012 10:22:08 -0400 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <5019F854.2050605@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> Message-ID: Questions: 1) Are there any complications with spanning multiple lines? ``` let foo = bar + baz + "some long string literal that takes us out to 80 chars" + qux + "and continued on this line" do something_else { ... ``` 2) What is the official style? On Wed, Aug 1, 2012 at 11:47 PM, Patrick Walton wrote: > On 08/01/2012 07:03 PM, Glenn Willen wrote: > >> I for one liked the clear and unambiguous rule: semicolon discards >> value, no-semicolon returns value. >> >> The idea of allowing uniform semicolon use is appealing, but it does >> seem to add complexity and mysteriousness. >> > > Actually, the only parser change was to throw away semicolons before the > end of the block. > > To be more concrete, the rules are: > > 1. The last expression is the value of the block, regardless of whether > there's a semicolon after it. (This seems like a simplification to me.) > > 2. "Statement positions" are defined as the position of any expression > immediately before a ";" (if that ";" has anything after it) and the last > value of a function declared to return unit. Given that: > > 3. The type of an expression in a statement position is ignored. > > 4. The types of the arms of a pattern match and the bodies of if/else > statements in statement position are ignored. > > I think the rules are pretty simple, but I'm biased :) > > Also, the pretty printer will never write a semicolon after an expression > in trailing position, so if you like the visual consistency the pretty > printer will preserve it for you. > > (Somewhat surprised at the response here, actually; this thread from 8 > months ago [1] had near-unanimity the other way!) > > Patrick > > [1]: https://mail.mozilla.org/**pipermail/rust-dev/2012-** > January/001263.html > > > ______________________________**_________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/**listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From pwalton at mozilla.com Thu Aug 2 07:41:56 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 07:41:56 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> Message-ID: <501A91B4.8050309@mozilla.com> On 08/02/2012 07:22 AM, Benjamin Striegel wrote: > Questions: > > 1) Are there any complications with spanning multiple lines? No. This change doesn't make Rust whitespace sensitive in any way. > 2) What is the official style? Right now the official style is what is currently done; semicolons are only used when ignoring a value. Patrick From ben.striegel at gmail.com Thu Aug 2 08:31:34 2012 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Thu, 2 Aug 2012 11:31:34 -0400 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501A91B4.8050309@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <501A91B4.8050309@mozilla.com> Message-ID: > Right now the official style is what is currently done; semicolons are only used when ignoring a value. Ah, so semicolons are absent by default? That seems like the right decision; making semicolons optional and yet canonicalizing their universal use almost certainly leads to contention down the road (cf Javascript). I'd be interested to see this happen, but I'd like to see how it works with unignorable return values. Do you have a branch that we can play with? On Thu, Aug 2, 2012 at 10:41 AM, Patrick Walton wrote: > On 08/02/2012 07:22 AM, Benjamin Striegel wrote: > >> Questions: >> >> 1) Are there any complications with spanning multiple lines? >> > > No. This change doesn't make Rust whitespace sensitive in any way. > > > 2) What is the official style? >> > > Right now the official style is what is currently done; semicolons are > only used when ignoring a value. > > Patrick > > > ______________________________**_________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/**listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gwillen at nerdnet.org Thu Aug 2 08:43:32 2012 From: gwillen at nerdnet.org (Glenn Willen) Date: Thu, 2 Aug 2012 08:43:32 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <5019F854.2050605@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> Message-ID: <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> On Aug 1, 2012, at 8:47 PM, Patrick Walton wrote: > > Actually, the only parser change was to throw away semicolons before the end of the block. > > To be more concrete, the rules are: > > 1. The last expression is the value of the block, regardless of whether there's a semicolon after it. (This seems like a simplification to me.) But blocks are now allowed to discard their values, where previously this was forbidden? That is, before, it was an error to say: fn foo() { 5 } But now it will be allowed? (I notice that in your first email you said that return values could already be ignored -- is my compiler just out of date on this question?) Glenn -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 243 bytes Desc: This is a digitally signed message part URL: From pwalton at mozilla.com Thu Aug 2 08:56:01 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 08:56:01 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <501A91B4.8050309@mozilla.com> Message-ID: <501AA311.1030905@mozilla.com> On 08/02/2012 08:31 AM, Benjamin Striegel wrote: > Ah, so semicolons are absent by default? That seems like the right > decision; making semicolons optional and yet canonicalizing their > universal use almost certainly leads to contention down the road (cf > Javascript). I think there's a bit of confusion here. This isn't an automatic semicolon insertion rule like JS, Scala, or Go have. It's sort of an automatic semicolon *deletion* rule if anything. Basically, it makes the presence of a semicolon not change the block result value. You still need to use semicolons to separate statements, as always. > I'd be interested to see this happen, but I'd like to see how it works > with unignorable return values. Do you have a branch that we can play with? This doesn't implement unignorable return values. I originally thought the two issues were intertwined, but they actually aren't; the semicolon rules can be relaxed while still allowing return values to be ignored. It's a backwards-compatible change for all intents and purposes. Patrick From pwalton at mozilla.com Thu Aug 2 08:58:03 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 08:58:03 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> Message-ID: <501AA38B.3060409@mozilla.com> On 08/02/2012 08:43 AM, Glenn Willen wrote: > But blocks are now allowed to discard their values, where previously this was forbidden? That is, before, it was an error to say: > > fn foo() { > 5 > } > > But now it will be allowed? (I notice that in your first email you said that return values could already be ignored -- is my compiler just out of date on this question?) Right, this would be allowed. By return values being ignored I mean that it's possible to write, say: fn f() -> int { return 3; } fn g() { f(); f(); } And the compiler won't complain or warn about the fact that the int was dropped. Patrick From dpreston at mozilla.com Thu Aug 2 09:10:59 2012 From: dpreston at mozilla.com (Donovan Preston) Date: Thu, 02 Aug 2012 12:10:59 -0400 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AA38B.3060409@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> Message-ID: <501AA693.3000104@mozilla.com> I would be more in favor of this proposal if the semicolon was not optional. Having the ability to have code that is identical except for a semicolon just doesn't feel right to me. On Thu Aug 2 11:58:03 2012, Patrick Walton wrote: > On 08/02/2012 08:43 AM, Glenn Willen wrote: >> But blocks are now allowed to discard their values, where previously > this was forbidden? That is, before, it was an error to say: >> >> fn foo() { >> 5 >> } >> >> But now it will be allowed? (I notice that in your first email you > said that return values could already be ignored -- is my compiler just > out of date on this question?) > > Right, this would be allowed. > > By return values being ignored I mean that it's possible to write, say: > > fn f() -> int { > return 3; > } > > fn g() { > f(); > f(); > } > > And the compiler won't complain or warn about the fact that the int > was dropped. > > Patrick > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From pwalton at mozilla.com Thu Aug 2 09:13:09 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 09:13:09 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AA693.3000104@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> Message-ID: <501AA715.4080704@mozilla.com> On 08/02/2012 09:10 AM, Donovan Preston wrote: > I would be more in favor of this proposal if the semicolon was not > optional. Having the ability to have code that is identical except for a > semicolon just doesn't feel right to me. If the semicolon were mandatory at the end of blocks, you'd have to write: let x = if cond { 3; } else { 5; } Which would be a non-starter, IMHO. Patrick From garethdanielsmith at gmail.com Thu Aug 2 09:15:18 2012 From: garethdanielsmith at gmail.com (Gareth Smith) Date: Thu, 2 Aug 2012 17:15:18 +0100 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <5019DD9F.7060809@mozilla.com> References: <5019DD9F.7060809@mozilla.com> Message-ID: > Thus this is in practice a backwards-compatible change intended to eliminate a good deal of toe-stubbing. IMHO the source of the toe-stubbing may be that rust has so many different ways to return a value: fn f() -> int { 42 } or fn f() -> int { ret 42 } or fn f() -> int { ret 42; } And ret cant be used inside lambdas. Except in do/for blocks. This proposal would add another variant: fn f() -> int { 42; } Most curly brace languages have just one way to return a value: int f() { return 42; } I would rather that I did not have to make the choice about which syntax to use. It doesn't seem like a meaningful choice. Gareth On 2 August 2012 02:53, Patrick Walton wrote: > Hi everyone, > > I have a patch that allows trailing semicolons in most cases in Rust code. > This means that code like this will compile: > > fn f(x: int) -> int { > x + 3; > } > > At the moment, this does not compile. You must write: > > fn f(x: int) -> int { > x + 3 > } > > For the most part, it does not alter the current rules as to whether > return values can be ignored. Return values can continue to be ignored in > almost all contexts; I didn't have to change any code in the compiler or > standard libraries. Thus this is in practice a backwards-compatible change > intended to eliminate a good deal of toe-stubbing. > > There is one subtle source of backwards-incompatibility though: You may > not drop the return value in sugared lambda expressions if you assign them > to a variable (i.e. if the type isn't immediately known). Thus this does > not do what it did before: > > // This return value is intended to be ignored. > fn f() -> int { > error!("Hi!"); > 3 > } > fn main() { > let g = || { f(); }; > error!("%?", g()); // prints 3, not () > } > > I personally feel that this particular gotcha is a small price to pay for > eliminating a frequent source of newcomer frustration, but it is worth > pointing out. Note that this does not apply for downward block closures; if > you're passing a lambda to a function, the return value of the lambda can > be safely ignored as before if the lambda is intended to return unit. > > Another downside is that some complexity is added to typechecking; the > typechecker is now aware of statement positions (which are expected to > return unit) and expression positions (which aren't). Note that Scala seems > to have already implemented a rule similar to this, so it isn't without > precedent; it also affects only how HM inference is invoked, not the nature > of unification itself. > > I'd like to get feedback as to whether this is a good idea. Comments > welcome! > > Patrick > ______________________________**_________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/**listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dpreston at mozilla.com Thu Aug 2 09:15:40 2012 From: dpreston at mozilla.com (Donovan Preston) Date: Thu, 02 Aug 2012 12:15:40 -0400 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AA715.4080704@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> <501AA715.4080704@mozilla.com> Message-ID: <501AA7AC.6040404@mozilla.com> On Thu Aug 2 12:13:09 2012, Patrick Walton wrote: > On 08/02/2012 09:10 AM, Donovan Preston wrote: >> I would be more in favor of this proposal if the semicolon was not >> optional. Having the ability to have code that is identical except for a >> semicolon just doesn't feel right to me. > > If the semicolon were mandatory at the end of blocks, you'd have to > write: > > let x = if cond { 3; } else { 5; } > > Which would be a non-starter, IMHO. Yes, it's definitely not pretty. At least it's a consistent rule to remember though; it's the inconsistency that makes me uncomfortable. From pwalton at mozilla.com Thu Aug 2 09:47:54 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 09:47:54 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> Message-ID: <501AAF3A.8050406@mozilla.com> On 08/02/2012 09:15 AM, Gareth Smith wrote: > > Thus this is in practice a backwards-compatible change intended to > eliminate a good deal of toe-stubbing. > > IMHO the source of the toe-stubbing may be that rust has so many > different ways to return a value: I'm not sure. The complaints I've seen (see the mailing list thread, or the bug [1], or various other private/public comments) are specifically about the trailing semicolon being significant. It also doesn't seem possible to fix this in the way you suggest. There are two ways: 1. Require "return", turning Rust back into a statement-oriented language instead of an expression-oriented one. I think it's too late to make such a drastic change. Besides, this is likely to make functional programmers unhappy. 2. Remove "return". This eliminates a huge amount of expressiveness. Many functional languages don't have "return", but they get around it with monads or exceptions, neither of which we have good support for. Also, Perl is an example of a curly-brace language in which both syntaxes work. JS is related -- it has the notion of a "completion value" for blocks, although you don't implicitly return the completion value. (As an aside, "return" not working inside lambda blocks is an issue, but that's basically because making it work would either introduce an unacceptable performance penalty, equivalent to C++ try/catch, or be inconsistent with the way it works in "for" blocks.) Patrick [1]: https://github.com/mozilla/rust/issues/1712 From gwillen at nerdnet.org Thu Aug 2 09:52:05 2012 From: gwillen at nerdnet.org (Glenn Willen) Date: Thu, 2 Aug 2012 09:52:05 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AA715.4080704@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> <501AA715.4080704@mozilla.com> Message-ID: On Aug 2, 2012, at 9:13 AM, Patrick Walton wrote: > If the semicolon were mandatory at the end of blocks, you'd have to write: > > let x = if cond { 3; } else { 5; } > > Which would be a non-starter, IMHO. So looking at this example made me realize that I do know one language that uses an optional-last-semicolon, which is Perl. And the house style there, which would probably come the house Rust style, is to use semicolons everywhere except one-liners like this. I personally still favor the current style, where the semicolon-or-lack-thereof has to reflect the return type of the function, and it's unambiguous whether a function's return type is the type of the final expression, or unit. This seems especially important in the non-function-item cases where the type has to be inferred. But now that I see that the new syntax is effectively the same one Perl uses, I'm not super worried about it, as long as we adopt the same house style that Perl programmers use: The semicolon is _always_ present, except in cases where it's too ugly (which is to say, one-liners.) (We could also adopt a house style of leaving it in where the value is ignored, and taking it out where the value is used; but if we did that we might as well not change the syntax. ;-) Glenn -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 243 bytes Desc: This is a digitally signed message part URL: From niko at alum.mit.edu Thu Aug 2 09:59:16 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 02 Aug 2012 09:59:16 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <5019DD9F.7060809@mozilla.com> References: <5019DD9F.7060809@mozilla.com> Message-ID: <501AB1E4.8000507@alum.mit.edu> My "official position" is unopposed. I personally like the rule about omitting the trailing semicolon, it makes it syntactically clearer when a value is being returned, but I understand some people have also complained about it. Your change seems to be a relatively simple way to make the presence or absence of a trailing semicolon irrelevant. One thing I am wondering about. The other unpopular semicolon rule (for which I am responsible) is the rule that a semicolon is required for a `do` or `for` with a non-unit result. This rule never bits me but I understand it occasionally bites users of the task API. Did you undo this rule? (And, if so, do we plan to replace with a whitespace-sensitive warning?) Niko On 8/1/12 6:53 PM, Patrick Walton wrote: > Hi everyone, > > I have a patch that allows trailing semicolons in most cases in Rust > code. This means that code like this will compile: > > fn f(x: int) -> int { > x + 3; > } > > At the moment, this does not compile. You must write: > > fn f(x: int) -> int { > x + 3 > } > > For the most part, it does not alter the current rules as to whether > return values can be ignored. Return values can continue to be ignored > in almost all contexts; I didn't have to change any code in the > compiler or standard libraries. Thus this is in practice a > backwards-compatible change intended to eliminate a good deal of > toe-stubbing. > > There is one subtle source of backwards-incompatibility though: You > may not drop the return value in sugared lambda expressions if you > assign them to a variable (i.e. if the type isn't immediately known). > Thus this does not do what it did before: > > // This return value is intended to be ignored. > fn f() -> int { > error!("Hi!"); > 3 > } > fn main() { > let g = || { f(); }; > error!("%?", g()); // prints 3, not () > } > > I personally feel that this particular gotcha is a small price to pay > for eliminating a frequent source of newcomer frustration, but it is > worth pointing out. Note that this does not apply for downward block > closures; if you're passing a lambda to a function, the return value > of the lambda can be safely ignored as before if the lambda is > intended to return unit. > > Another downside is that some complexity is added to typechecking; the > typechecker is now aware of statement positions (which are expected to > return unit) and expression positions (which aren't). Note that Scala > seems to have already implemented a rule similar to this, so it isn't > without precedent; it also affects only how HM inference is invoked, > not the nature of unification itself. > > I'd like to get feedback as to whether this is a good idea. Comments > welcome! > > Patrick > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From niko at alum.mit.edu Thu Aug 2 10:03:10 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 02 Aug 2012 10:03:10 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AAF3A.8050406@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <501AAF3A.8050406@mozilla.com> Message-ID: <501AB2CE.3040605@alum.mit.edu> There is another option. Right now we have a number of "expressions" that can only really be used as statements: a = b a += b loop { } while cond { } return ... These all have unit (or bottom) return type. We could require semicolons after these. At least you would not then be able to write: if cond { return } but rather if cond { return; } and not fn foo() -> int { return 22 } but rather fn foo() -> int { return 22; } Niko On 8/2/12 9:47 AM, Patrick Walton wrote: > On 08/02/2012 09:15 AM, Gareth Smith wrote: >> > Thus this is in practice a backwards-compatible change intended to >> eliminate a good deal of toe-stubbing. >> >> IMHO the source of the toe-stubbing may be that rust has so many >> different ways to return a value: > > I'm not sure. The complaints I've seen (see the mailing list thread, > or the bug [1], or various other private/public comments) are > specifically about the trailing semicolon being significant. > > It also doesn't seem possible to fix this in the way you suggest. > There are two ways: > > 1. Require "return", turning Rust back into a statement-oriented > language instead of an expression-oriented one. I think it's too late > to make such a drastic change. Besides, this is likely to make > functional programmers unhappy. > > 2. Remove "return". This eliminates a huge amount of expressiveness. > Many functional languages don't have "return", but they get around it > with monads or exceptions, neither of which we have good support for. > > Also, Perl is an example of a curly-brace language in which both > syntaxes work. JS is related -- it has the notion of a "completion > value" for blocks, although you don't implicitly return the completion > value. > > (As an aside, "return" not working inside lambda blocks is an issue, > but that's basically because making it work would either introduce an > unacceptable performance penalty, equivalent to C++ try/catch, or be > inconsistent with the way it works in "for" blocks.) > > Patrick > > [1]: https://github.com/mozilla/rust/issues/1712 > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From erick.tryzelaar at gmail.com Thu Aug 2 10:07:46 2012 From: erick.tryzelaar at gmail.com (Erick Tryzelaar) Date: Thu, 2 Aug 2012 10:07:46 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> <501AA715.4080704@mozilla.com> Message-ID: I'm coming from functional-programming-land, so I'm quite fond of our current scheme. These seems a bit surprising to me: fn f() -> int { 3 } fn g() -> int { 4 } fn h() -> int { f(); // result ignored g(); // result returned } I'm probably pretty biased, but I don't think this is a complicated rule to learn. The type checker will complain if you thought `fn f() -> int { 3; }` returns `3`, so I expect it's something most newbies will run into once or twice before they get the hang of it. From gwillen at nerdnet.org Thu Aug 2 10:08:31 2012 From: gwillen at nerdnet.org (Glenn Willen) Date: Thu, 2 Aug 2012 10:08:31 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AB2CE.3040605@alum.mit.edu> References: <5019DD9F.7060809@mozilla.com> <501AAF3A.8050406@mozilla.com> <501AB2CE.3040605@alum.mit.edu> Message-ID: <13EED44E-1C73-4F7C-9938-148CD5D68F13@nerdnet.org> I think the ideal rule is one that can be easily learned by observation of existing code. I don't think this is such a rule. I think the current rule is such a rule, but it seems some people disagree. :-) The new rule has the disadvantage that it's hard to learn what the actual rule is, versus the house style, from reading examples; but the advantage that it doesn't matter what you learn since your code will still work. Glenn On Aug 2, 2012, at 10:03 AM, Niko Matsakis wrote: > There is another option. Right now we have a number of "expressions" that can only really be used as statements: > > a = b > a += b > loop { } > while cond { } > return > ... > > These all have unit (or bottom) return type. We could require semicolons after these. At least you would not then be able to write: > > if cond { return } > > but rather > > if cond { return; } > > and not > > fn foo() -> int { return 22 } > > but rather > > fn foo() -> int { return 22; } > > > > > Niko > > On 8/2/12 9:47 AM, Patrick Walton wrote: >> On 08/02/2012 09:15 AM, Gareth Smith wrote: >>> > Thus this is in practice a backwards-compatible change intended to >>> eliminate a good deal of toe-stubbing. >>> >>> IMHO the source of the toe-stubbing may be that rust has so many >>> different ways to return a value: >> >> I'm not sure. The complaints I've seen (see the mailing list thread, or the bug [1], or various other private/public comments) are specifically about the trailing semicolon being significant. >> >> It also doesn't seem possible to fix this in the way you suggest. There are two ways: >> >> 1. Require "return", turning Rust back into a statement-oriented language instead of an expression-oriented one. I think it's too late to make such a drastic change. Besides, this is likely to make functional programmers unhappy. >> >> 2. Remove "return". This eliminates a huge amount of expressiveness. Many functional languages don't have "return", but they get around it with monads or exceptions, neither of which we have good support for. >> >> Also, Perl is an example of a curly-brace language in which both syntaxes work. JS is related -- it has the notion of a "completion value" for blocks, although you don't implicitly return the completion value. >> >> (As an aside, "return" not working inside lambda blocks is an issue, but that's basically because making it work would either introduce an unacceptable performance penalty, equivalent to C++ try/catch, or be inconsistent with the way it works in "for" blocks.) >> >> Patrick >> >> [1]: https://github.com/mozilla/rust/issues/1712 >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > > > !DSPAM:501aadaa175111014834540! > -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 243 bytes Desc: This is a digitally signed message part URL: From erick.tryzelaar at gmail.com Thu Aug 2 10:11:54 2012 From: erick.tryzelaar at gmail.com (Erick Tryzelaar) Date: Thu, 2 Aug 2012 10:11:54 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AB2CE.3040605@alum.mit.edu> References: <5019DD9F.7060809@mozilla.com> <501AAF3A.8050406@mozilla.com> <501AB2CE.3040605@alum.mit.edu> Message-ID: On Thu, Aug 2, 2012 at 10:03 AM, Niko Matsakis wrote: > > These all have unit (or bottom) return type. We could require semicolons > after these. At least you would not then be able to write: > > if cond { return } > > but rather > > if cond { return; } > > and not > > fn foo() -> int { return 22 } > > but rather > > fn foo() -> int { return 22; } I like this. I think all of my returns have a semicolon, whether or not they actually need them. What about for fail? Is there a good example of using fail as an expression? From niko at alum.mit.edu Thu Aug 2 10:30:29 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 02 Aug 2012 10:30:29 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> <501AA715.4080704@mozilla.com> Message-ID: <501AB935.8090206@alum.mit.edu> On 8/2/12 10:07 AM, Erick Tryzelaar wrote: > fn h() -> int { > f(); // result ignored > g(); // result returned > } It's true, I feel like the current scheme does a better job of highlighting when a seemingly unused value is significant. I don't know, I always liked the current rule regarding final values and?of all our semicolon rules?it seems the easiest to learn. Probably the weirdest one is the one which I introduced regarding return values of what are now called `do` and `for` statements. But that can (and perhaps should) be separately addressed. Niko From pwalton at mozilla.com Thu Aug 2 10:35:54 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 10:35:54 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> <501AA715.4080704@mozilla.com> Message-ID: <501ABA7A.8080009@mozilla.com> On 8/2/12 9:52 AM, Glenn Willen wrote: > But now that I see that the new syntax is effectively the same one Perl uses, I'm not super worried about it, as long as we adopt the same house style that Perl programmers use: The semicolon is _always_ present, except in cases where it's too ugly (which is to say, one-liners.) > > (We could also adopt a house style of leaving it in where the value > is ignored, and taking it out where the value is used; but if we did that we might as well not change the syntax. ;-) I like the idea of having the trailing semicolon be our house style, except in the case of one-liners. I could rig up the pretty-printer to do that. Ultimately I think this comes down to the fact that we're bridging two worlds: we're trying to cater to the functional programming world, which is used to semicolon as a statement separator, and the C/C++ world, which is used to putting a semicolon at the end of every block. Patrick From lists.rust at dbp.mm.st Thu Aug 2 10:37:42 2012 From: lists.rust at dbp.mm.st (Daniel Patterson) Date: Thu, 2 Aug 2012 13:37:42 -0400 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501ABA7A.8080009@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> <1C2AB957-BDB9-4D99-BE6F-024D9CEB217C@nerdnet.org> <501AA38B.3060409@mozilla.com> <501AA693.3000104@mozilla.com> <501AA715.4080704@mozilla.com> <501ABA7A.8080009@mozilla.com> Message-ID: I personally think the current/old rule is good; at least to me, it is completely clear what is going on - semicolon means terminate statement, and the last (unterminated) statement is returned, unless a short-circuit return exists. Mixing functional/imperative code is tricky, but I think this rule actually works pretty well. Learning it took no time, especially compared to the other less-obvious syntax/semantics of rust. Dropping return values seems like a solution to something that isn't a problem (and just makes things less clear/more bug prone) - because if I write: fn something() { blah(); blah() } and want it to return the result of the second function (and thus, intentionally leave off the semicolon) but forgot to write (or update, if it used to return unit) the signature, it will simply drop it. Whereas without dropping values, and with the current rules, this would be a compile error - meaning I either have to specify that I want to drop it explicitly, or fix the signature. This seems like a win.On Aug 2, 2012, at 1:35 PM, Patrick Walton wrote: > On 8/2/12 9:52 AM, Glenn Willen wrote: >> But now that I see that the new syntax is effectively the same one > Perl uses, I'm not super worried about it, as long as we adopt the same > house style that Perl programmers use: The semicolon is _always_ > present, except in cases where it's too ugly (which is to say, one-liners.) >> >> (We could also adopt a house style of leaving it in where the value >> is > ignored, and taking it out where the value is used; but if we did that > we might as well not change the syntax. ;-) > > I like the idea of having the trailing semicolon be our house style, except in the case of one-liners. I could rig up the pretty-printer to do that. > > Ultimately I think this comes down to the fact that we're bridging two worlds: we're trying to cater to the functional programming world, which is used to semicolon as a statement separator, and the C/C++ world, which is used to putting a semicolon at the end of every block. > > Patrick > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From pwalton at mozilla.com Thu Aug 2 10:47:36 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 10:47:36 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501AB1E4.8000507@alum.mit.edu> References: <5019DD9F.7060809@mozilla.com> <501AB1E4.8000507@alum.mit.edu> Message-ID: <501ABD38.10703@mozilla.com> On 8/2/12 9:59 AM, Niko Matsakis wrote: > My "official position" is unopposed. I personally like the rule about > omitting the trailing semicolon, it makes it syntactically clearer when > a value is being returned, but I understand some people have also > complained about it. Your change seems to be a relatively simple way to > make the presence or absence of a trailing semicolon irrelevant. > > One thing I am wondering about. The other unpopular semicolon rule (for > which I am responsible) is the rule that a semicolon is required for a > `do` or `for` with a non-unit result. This rule never bits me but I > understand it occasionally bites users of the task API. Did you undo > this rule? (And, if so, do we plan to replace with a > whitespace-sensitive warning?) I left it alone. I like the idea of a whitespace-sensitive warning, but I don't feel particularly strongly. Patrick From emmanuel.surleau at gmail.com Thu Aug 2 12:51:01 2012 From: emmanuel.surleau at gmail.com (Emmanuel Surleau) Date: Thu, 2 Aug 2012 21:51:01 +0200 Subject: [rust-dev] Polymorphism & default parameters in rust Message-ID: <20120802195101.GB15038@mercurialalchemist> Hi, I'm new to rust, and I'm struggling to find an elegant way to work with default parameters. I'm trying to implement in rust the equivalent of the following Python line: def flag(self, name, desc, short_name=None, max_count=1, banner=None): ... The idea is to offer a "simple" API (with only name and desc mandatory, while making available number of advanced options if needed). My first move was to try polymorphism: fn a(x: ~str) -> ~str { #fmt("First function with %s", x) } fn a(x: ~str, y: ~str) -> ~str { #fmt("Second function with %s and %s", x, y) } fn main() { #info("Result: "); } Oddly enough, this compiles, but the first function is shadowed by the second, so attempting a(~"something") does not compile. I assume this is not an intended behaviour. Further research hasn't turned any solution. Is there some idiomatic way in rust of having defaults for parameters? Cheers, Emm From catamorphism at gmail.com Thu Aug 2 13:00:43 2012 From: catamorphism at gmail.com (Tim Chevalier) Date: Thu, 2 Aug 2012 13:00:43 -0700 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: <20120802195101.GB15038@mercurialalchemist> References: <20120802195101.GB15038@mercurialalchemist> Message-ID: On Thu, Aug 2, 2012 at 12:51 PM, Emmanuel Surleau wrote: > Hi, > > I'm new to rust, and I'm struggling to find an elegant way to work with default > parameters. > > I'm trying to implement in rust the equivalent of the following Python line: > > def flag(self, name, desc, short_name=None, max_count=1, banner=None): > ... > > The idea is to offer a "simple" API (with only name and desc mandatory, while > making available number of advanced options if needed). > > My first move was to try polymorphism: > > fn a(x: ~str) -> ~str { > #fmt("First function with %s", x) > } > > fn a(x: ~str, y: ~str) -> ~str { > #fmt("Second function with %s and %s", x, y) > } > > fn main() { > #info("Result: "); > } > > Oddly enough, this compiles, but the first function is shadowed by the second, > so attempting a(~"something") does not compile. I assume this is not an intended > behaviour. > Hi, Emmanuel -- I believe that the behavior you're observing is a bug; you shouldn't be able to declare two top-level function items with the same name, even if the types differ. So please file an issue with this code: https://github.com/mozilla/rust/issues Thanks. > Further research hasn't turned any solution. Is there some idiomatic way in rust > of having defaults for parameters? A simple way to do it is with option types: fn a(x: ~str, y: option<~str>) -> ~str { /* do whatever */ } fn a_1(x: ~str) -> ~str { a(x, none) } You may be able to use traits and impls to overload the name a, but if you don't mind giving the different functions different names, this way doesn't require any fancy ideas. Cheers, Tim -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "Debate is useless when one participant denies the full dignity of the other." -- Eric Berndt From ted.horst at earthlink.net Thu Aug 2 18:05:13 2012 From: ted.horst at earthlink.net (Ted Horst) Date: Thu, 2 Aug 2012 20:05:13 -0500 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <5019F854.2050605@mozilla.com> Message-ID: I've hesitated to comment so far because I didn't understand what people were complaining about, but I like the current system better than any of these proposals. Coming from mostly C style languages, I didn't have any problem understanding it or using it. Ted From pwalton at mozilla.com Thu Aug 2 18:20:26 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 18:20:26 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <5019DD9F.7060809@mozilla.com> References: <5019DD9F.7060809@mozilla.com> Message-ID: <501B275A.40403@mozilla.com> There is another issue I forgot to mention, which is the match clause separator. Currently, "match" (formerly "alt") clauses must either be separated by a closing brace '}' or a comma ','. We can't use '|' like ML because of bitwise-or. So we have: match foo { 'a' => 1, 'b' => 2, 'c' => 3 } With semicolons this perhaps blends in better: match foo { 'a' => 1; 'b' => 2; 'c' => 3; } But this would require semicolons to be ignorable, or else it doesn't fit in well with the rest of the language. Patrick From me at kevincantu.org Thu Aug 2 19:04:21 2012 From: me at kevincantu.org (Kevin Cantu) Date: Thu, 2 Aug 2012 19:04:21 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501B275A.40403@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <501B275A.40403@mozilla.com> Message-ID: Why wouldn't that fit in? I'm missing something here. On Thu, Aug 2, 2012 at 6:20 PM, Patrick Walton wrote: > There is another issue I forgot to mention, which is the match clause > separator. > > Currently, "match" (formerly "alt") clauses must either be separated by a > closing brace '}' or a comma ','. We can't use '|' like ML because of > bitwise-or. > > So we have: > > match foo { > 'a' => 1, > 'b' => 2, > 'c' => 3 > } > > With semicolons this perhaps blends in better: > > match foo { > 'a' => 1; > 'b' => 2; > 'c' => 3; > } > > But this would require semicolons to be ignorable, or else it doesn't fit in > well with the rest of the language. > > > Patrick > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From pwalton at mozilla.com Thu Aug 2 19:05:46 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 19:05:46 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: References: <5019DD9F.7060809@mozilla.com> <501B275A.40403@mozilla.com> Message-ID: <501B31FA.2060408@mozilla.com> On 8/2/12 7:04 PM, Kevin Cantu wrote: > Why wouldn't that fit in? I'm missing something here. Because ordinarily a semicolon means that the value is returned, but in this case it wouldn't. A clearer example would probably be: let x = match foo { 'a' => 1; 'b' => 2; 'c' => 3; } log!("%d", x); Patrick From pwalton at mozilla.com Thu Aug 2 19:06:17 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 02 Aug 2012 19:06:17 -0700 Subject: [rust-dev] RFC: Ignore trailing semicolons In-Reply-To: <501B31FA.2060408@mozilla.com> References: <5019DD9F.7060809@mozilla.com> <501B275A.40403@mozilla.com> <501B31FA.2060408@mozilla.com> Message-ID: <501B3219.4010209@mozilla.com> On 8/2/12 7:05 PM, Patrick Walton wrote: > On 8/2/12 7:04 PM, Kevin Cantu wrote: >> Why wouldn't that fit in? I'm missing something here. > > Because ordinarily a semicolon means that the value is returned, but in > this case it wouldn't. Err, ordinarily a semicolon means that the value is *ignored*. Patrick From Stefan.Plantikow at googlemail.com Sat Aug 4 06:23:42 2012 From: Stefan.Plantikow at googlemail.com (Stefan Plantikow) Date: Sat, 4 Aug 2012 15:23:42 +0200 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: References: <20120802195101.GB15038@mercurialalchemist> Message-ID: <47FB08E3-2227-4AD2-B873-2F82DE50783B@googlemail.com> Hi, Am 02.08.2012 um 22:00 schrieb Tim Chevalier : > > You may be able to use traits and impls to overload the name a, but if > you don't mind giving the different functions different names, this > way doesn't require any fancy ideas. > I keep wondering if we should have a way to specify a default value per type, perhaps via a specific trait that just provides a default() call (e.g. none for option). This way optional arguments could be implemented with a simple rule: All missing arguments are replaced with calls to default() if the type implements that. Cheers, Stefan. From pwalton at mozilla.com Sat Aug 4 09:53:32 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Sat, 04 Aug 2012 09:53:32 -0700 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: <20120802195101.GB15038@mercurialalchemist> References: <20120802195101.GB15038@mercurialalchemist> Message-ID: <501D538C.4040909@mozilla.com> On 08/02/2012 12:51 PM, Emmanuel Surleau wrote: > Hi, > > I'm new to rust, and I'm struggling to find an elegant way to work with default > parameters. Generally we've been experimenting with method chaining to achieve things like default and named parameters in Rust. See the task builder API for an example: https://github.com/mozilla/rust/blob/incoming/src/libcore/task.rs#L197 So I can see your use case being something like: let flag = Flag("verbose", "Maximum verbosity").short_name("v"); To implement this you'd write: struct Flag { name: &str; desc: &str; short_name: option<&str>; max_count: uint; banner: option<&str>; } // Constructor fn Flag(name: &str, desc: &str) -> Flag { Flag { name: name, desc: desc, short_name: none, max_count: 1, banner: none } } impl Flag { fn short_name(self, short_name: &str) -> Flag { Flag { short_name: some(short_name) with self } } fn max_count(self, max_count: uint) -> Flag { Flag { max_count: max_count with self } } fn banner(self, banner: &str) -> Flag { Flag { banner: some(banner) with self } } } (Note that this depends on the functional record update "with" syntax working for structs, which it doesn't yet.) If this style catches on it'd probably be nice to have a macro to generate the mutators (fn short_name, fn max_count, fn banner). Then instead of the "impl { ... }" above you'd write something like: make_setter!(Flag.short_name: option<&str>, WrapOption); make_setter!(Flag.max_count: uint); make_setter!(Flag.banner: option<&str>, WrapOption); (Assuming that WrapOption is a special flag to the macro to indicate that the value should automatically be wrapped in "some"). How does this sound? Patrick From matthieu.monrocq at gmail.com Sat Aug 4 11:20:02 2012 From: matthieu.monrocq at gmail.com (Matthieu Monrocq) Date: Sat, 4 Aug 2012 20:20:02 +0200 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: <501D538C.4040909@mozilla.com> References: <20120802195101.GB15038@mercurialalchemist> <501D538C.4040909@mozilla.com> Message-ID: On Sat, Aug 4, 2012 at 6:53 PM, Patrick Walton wrote: > On 08/02/2012 12:51 PM, Emmanuel Surleau wrote: > >> Hi, >> >> I'm new to rust, and I'm struggling to find an elegant way to work with >> default >> parameters. >> > > Generally we've been experimenting with method chaining to achieve things > like default and named parameters in Rust. See the task builder API for an > example: > > https://github.com/mozilla/**rust/blob/incoming/src/**libcore/task.rs#L197 > > So I can see your use case being something like: > > let flag = Flag("verbose", "Maximum verbosity").short_name("v"); > > To implement this you'd write: > > struct Flag { > name: &str; > desc: &str; > short_name: option<&str>; > max_count: uint; > banner: option<&str>; > } > > // Constructor > fn Flag(name: &str, desc: &str) -> Flag { > Flag { > name: name, > desc: desc, > short_name: none, > max_count: 1, > banner: none > } > } > > impl Flag { > fn short_name(self, short_name: &str) -> Flag { > Flag { short_name: some(short_name) with self } > } > fn max_count(self, max_count: uint) -> Flag { > Flag { max_count: max_count with self } > } > fn banner(self, banner: &str) -> Flag { > Flag { banner: some(banner) with self } > } > } > > (Note that this depends on the functional record update "with" syntax > working for structs, which it doesn't yet.) > > If this style catches on it'd probably be nice to have a macro to generate > the mutators (fn short_name, fn max_count, fn banner). Then instead of the > "impl { ... }" above you'd write something like: > > make_setter!(Flag.short_name: option<&str>, WrapOption); > make_setter!(Flag.max_count: uint); > make_setter!(Flag.banner: option<&str>, WrapOption); > > (Assuming that WrapOption is a special flag to the macro to indicate that > the value should automatically be wrapped in "some"). > > How does this sound? > > Patrick > > Verbose. -- Matthieu -------------- next part -------------- An HTML attachment was scrubbed... URL: From pwalton at mozilla.com Sat Aug 4 11:28:56 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Sat, 04 Aug 2012 11:28:56 -0700 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: References: <20120802195101.GB15038@mercurialalchemist> <501D538C.4040909@mozilla.com> Message-ID: <501D69E8.3060105@mozilla.com> On 08/04/2012 11:20 AM, Matthieu Monrocq wrote: > Verbose. > > -- Matthieu Perhaps, but we can write macros for most of this. In general, I'd like to see whether we can avoid adding new features at this stage; the language complexity budget is pretty strained. Patrick From lists.rust at dbp.mm.st Sat Aug 4 11:58:06 2012 From: lists.rust at dbp.mm.st (Daniel Patterson) Date: Sat, 4 Aug 2012 14:58:06 -0400 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: <501D69E8.3060105@mozilla.com> References: <20120802195101.GB15038@mercurialalchemist> <501D538C.4040909@mozilla.com> <501D69E8.3060105@mozilla.com> Message-ID: Having default parameters seems like overloading, which at least to me, is not all that desirable (when avoidable). Is it that hard to do: fn f(a : int, b : int) -> int { ? } fn f_s(b : int) -> int { f(10, b) } You get the default param behavior, without the magic of overloading, and it is clear from application what you are doing. This costs one line of code, and having a separate name for the defaulted version? On Aug 4, 2012, at 2:28 PM, Patrick Walton wrote: > On 08/04/2012 11:20 AM, Matthieu Monrocq wrote: >> Verbose. >> >> -- Matthieu > > Perhaps, but we can write macros for most of this. > > In general, I'd like to see whether we can avoid adding new features at this stage; the language complexity budget is pretty strained. > > Patrick > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From pwalton at mozilla.com Sat Aug 4 12:10:57 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Sat, 04 Aug 2012 12:10:57 -0700 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: References: <20120802195101.GB15038@mercurialalchemist> <501D538C.4040909@mozilla.com> <501D69E8.3060105@mozilla.com> Message-ID: <501D73C1.2070604@mozilla.com> On 08/04/2012 11:58 AM, Daniel Patterson wrote: > You get the default param behavior, without the magic of overloading, > and it is clear from application what you are doing. This costs one > line of code, and having a separate name for the defaulted version? Yes. This should be plan A for Rust programmers; plan B is method chaining :) As an aside, the prevailing Rust style is clarity over cleverness, even if that results in a little less flexibility. For example, our map function in the standard library isn't as flexible as it could be; you can't map from a mutable vector to an immutable one or from an immutable vector to a mutable one with one function. Scala's map function does let you do that, and we could conceivably have duplicated that functionality with traits. But we really wanted the signature of the map function to be: fn map(v: [T], f: &fn(T)->U) -> [U] Instead of something more complicated. As for named and optional parameters, I'm not opposed to them if they prove necessary, but my thinking right now is that they're not a version 1.0 feature. Patrick From graydon at mozilla.com Sat Aug 4 12:15:51 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Sat, 04 Aug 2012 12:15:51 -0700 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: <20120802195101.GB15038@mercurialalchemist> References: <20120802195101.GB15038@mercurialalchemist> Message-ID: <501D74E7.9070604@mozilla.com> On 02/08/2012 12:51 PM, Emmanuel Surleau wrote: > Hi, > > I'm new to rust, and I'm struggling to find an elegant way to work with default > parameters. We don't have explicit support for it yet. Nor named params, varargs, or generalized overloading (we only allow overloading via traits). There is room in the syntax and semantics for this in the future, but I agree with Patrick that running experiments on combining such features is past scope for the "stabilize for 1.0" roadmap; we already have a _very_ full plate and have been trying to get the language to stop moving for two years now. It's slowing but we're trying to cut-in-order-to-ship pretty aggressively. This subset of features is comparatively non-essential (lots of language lack it) and can be worked around several ways, as people have suggested: 1. pass option and the callers can say 'none' for defaults. 2. make a separate default-passing fn 3. use a method-chaining "fluent interface" approach if you want the type system to help you enforce that only certain combinations of arguments are legit 4. use a macro 5. overload via traits If none of these fit the bill, well, we might explore the space we left open for this in the future. I won't close a bug on it or anything, it's a legit feature. Just not one I'm going to want to pull into the language this time around. -Graydon From lists.rust at dbp.mm.st Sat Aug 4 12:19:11 2012 From: lists.rust at dbp.mm.st (Daniel Patterson) Date: Sat, 4 Aug 2012 15:19:11 -0400 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: References: <20120802195101.GB15038@mercurialalchemist> <501D538C.4040909@mozilla.com> <501D69E8.3060105@mozilla.com> Message-ID: <95786487-874C-468E-9472-5798E3E29709@dbp.mm.st> Another option, that a lot of haskell code uses if you need to support all sorts of combinations, is to use record update syntax, so you would do something along the lines of (trying to mimic patricks syntax): f(Options { a : 10 with defaultOptions}) where defaultOptions is: Options { a : 10, b : 10 } and f is: fn f(opts : Options) -> int { ... } Here the (proposed) syntax doesn't make it as clean as with haskell, where it would look like: f(defaultOptions { a : 10}) But it is the same basic idea?. and also isn't particularly verbose (i.e., there is not any boiler plate)? in that case though the method chaining seems better: f(defaultOptions.a(10)) Though if the record update syntax was lighter weight (it doesn't exist yet, yes?), it might also be viable. On Aug 4, 2012, at 2:58 PM, Daniel Patterson wrote: > Having default parameters seems like overloading, which at least to me, is not all that desirable (when avoidable). > > Is it that hard to do: > > fn f(a : int, b : int) -> int { > ? > } > fn f_s(b : int) -> int { f(10, b) } > > You get the default param behavior, without the magic of overloading, and it is clear from application what you are doing. This costs one line of code, and having a separate name for the defaulted version? > > On Aug 4, 2012, at 2:28 PM, Patrick Walton wrote: > >> On 08/04/2012 11:20 AM, Matthieu Monrocq wrote: >>> Verbose. >>> >>> -- Matthieu >> >> Perhaps, but we can write macros for most of this. >> >> In general, I'd like to see whether we can avoid adding new features at this stage; the language complexity budget is pretty strained. >> >> Patrick >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From emmanuel.surleau at gmail.com Sun Aug 5 10:50:02 2012 From: emmanuel.surleau at gmail.com (Emmanuel Surleau) Date: Sun, 5 Aug 2012 19:50:02 +0200 Subject: [rust-dev] Polymorphism & default parameters in rust In-Reply-To: <501D74E7.9070604@mozilla.com> References: <20120802195101.GB15038@mercurialalchemist> <501D74E7.9070604@mozilla.com> Message-ID: <20120805175002.GA2710@mercurialalchemist> On Sat, Aug 04, 2012 at 12:15:51PM -0700, Graydon Hoare wrote: > On 02/08/2012 12:51 PM, Emmanuel Surleau wrote: > >Hi, > > > >I'm new to rust, and I'm struggling to find an elegant way to work with default > >parameters. > > We don't have explicit support for it yet. Nor named params, > varargs, or generalized overloading (we only allow overloading via > traits). > > There is room in the syntax and semantics for this in the future, > but I agree with Patrick that running experiments on combining such > features is past scope for the "stabilize for 1.0" roadmap; we > already have a _very_ full plate and have been trying to get the > language to stop moving for two years now. It's slowing but we're > trying to cut-in-order-to-ship pretty aggressively. This subset of > features is comparatively non-essential (lots of language lack it) > and can be worked around several ways, as people have suggested: > > 1. pass option and the callers can say 'none' for defaults. > 2. make a separate default-passing fn > 3. use a method-chaining "fluent interface" approach if you want > the type system to help you enforce that only certain combinations > of arguments are legit > 4. use a macro > 5. overload via traits > > If none of these fit the bill, well, we might explore the space we > left open for this in the future. I won't close a bug on it or > anything, it's a legit feature. Just not one I'm going to want to > pull into the language this time around. Option 1 is an issue when dealing with larger data structures, you're going to end up with things like fn(1,2,3,none,none,4). I guess I'll go with method chaining for now, as it seems the cleanest solution. Let me add a side note to say I truly appreciate the depth and open-mindedness of the answers I have gotten. I am also sympathetic to your argument concerning the stabilization of the language. I'm definitely looking forward to rust 1.0. Cheers, Emm From lists.rust at dbp.mm.st Mon Aug 6 13:49:21 2012 From: lists.rust at dbp.mm.st (Daniel Patterson) Date: Mon, 6 Aug 2012 16:49:21 -0400 Subject: [rust-dev] Functional record update syntax - with different types Message-ID: The current syntax for record updates: struct A { a : int; b : int; } let some_a = A { a : 10, b : 10 }; let other_a = A { a : 0 with some_a }; Sort of hints at being able to combine records of different types; because if the type of other_a is guaranteed by the type of some_a, then the leading A seems redundant. I'm not sure if this is actually desired behavior, but it seems like the following should work: struct B { a : int; b : int; c : int; } let some_b = B { c : 10 with some_a }; Where B would have to contain all the fields of A. Or perhaps A would just have to have all of the fields in B not specified in the record. I know that there has been talk about dropping structural records in favor of exclusively nominal ones (or perhaps this has already happened?). In a world of only nominal records, I'm not sure if this is actually desired behavior, and would actually think that not allowing this and using an alternate syntax for record updates (similar to how Haskell does this) would be better: let other_a2 = some_a { a : 0 }; But with structural records, the mixing seems to make sense (and you could even see A { with some_b } as a way to drop the extra fields?). Thoughts? From graydon at mozilla.com Tue Aug 7 10:06:25 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Tue, 07 Aug 2012 10:06:25 -0700 Subject: [rust-dev] Ragel support for Rust In-Reply-To: References: Message-ID: <50214B11.9080000@mozilla.com> On 12-07-29 12:20 PM, Tim Chevalier wrote: >> Unfortunately there are some pretty severe performance issues at the moment. >> Ragel supports two state machine styles, table-driven and goto-driven. My >> backend uses tables, but since Rust doesn't yet support global constant >> vectors, I need to malloc the state machine table on every function call. This >> results in the [ragel-based url >> parser](https://github.com/erickt/ragel/blob/rust/examples/rust/url.rl) >> being about >> 10 times slower than the equivalent table-based parser in OCaml. You can see >> the generated code [here](https://gist.github.com/3200980). > > There's an open bug on vector constants: > > https://github.com/mozilla/rust/issues/571 > > It's assigned to me (though I haven't done anything on it yet), so > feel free to bug me about it :-) Yeah, I'm doing this (all the const-exprs) presently. There might be enough in there now to point ragel at. Constant records and tuples work, as do const vectors and &-ptrs to consts. No slices yet. Still lots to do. > This sounds like the open bug on labelled break and continue, as Patrick said: > > https://github.com/mozilla/rust/issues/2216 > > which is currently unassigned. As per #217, we decided not to support > general tail calls, but that doesn't mean we can't support tail calls > just for the special labelled break/continue form. Yeah. I think that might be adequate, at least for building-atop with a macro or other extension. Assuming we permit a 'sideways again' that transfers from one labeled loop to another (at the same or higher nesting level). The key thing you want is direct branching to your current state (rather than indirect off a 'current state' variable) and direct jumps from one state to another; the rest (argument passing etc.) can be encoded at no cost through local variables. The fast control transfers can't. I do slightly wonder if the labeled break/again forms will mutate into general gotos. I hope not. -Graydon From niko at alum.mit.edu Wed Aug 8 15:14:43 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Wed, 08 Aug 2012 15:14:43 -0700 Subject: [rust-dev] mode removal Message-ID: <5022E4D3.1060405@alum.mit.edu> I am working now on removing modes from isolated modules in rustc. The basic idea is to employ these two lint modes: #[warn(deprecated_mode)]; #[warn(deprecated_pattern)]; They both give warnings when you are relying on defaults that will change, possibly for the worse. Both of them have an idea of a type that is "expensive or inadvisable to copy". This consists of all types that are not implicitly copyable (that is, unique ptrs or types with mutable contents) but also values which are large (more than 4 fields, I think?), type parameters, and some other categories I don't recall. It also always warns about ~str or ~[], even though by default those are considered implicitly copyable. In the case of function parameters, if you get a warning, you have two choices. (1) Convert the type to something implicitly copyable, usually by changing the type T to a region pointer &T. (2) If you did want a copy, then use by-copy mode (+). If you use any other mode besides the default or +, you will get a warning. In the case of patterns, you can choose either the copy or the ref keyword. So you can write: match foo { bar(ref x) => {...} } Note that `ref x` will mean that `x` has a region type `&T`. If you wanted to copy the value out, you could do: match foo { bar(copy x) => {...} } in which case `x` will have the type `T`. When converting, you will often hit borders between code that is region converted and code that is not. Here you may need to add dummy `*` or `&` to make the type work out. For example, if you call a function with a parameter that uses `&&` mode but you have a value of type `&T`, you have to write `foo(*bar)`, even though no pointer deref actually occurs. This is similar to C++ and the mismatch betweeen `T&` and `T*`. I am currently working on converting the `infer.rs` module and some of the type checker. It's somewhat tedious work. It may be worth waiting until I'm done because I encounter small bugs from time to time that require snapshots. Niko From banderson at mozilla.com Tue Aug 14 16:35:20 2012 From: banderson at mozilla.com (Brian Anderson) Date: Tue, 14 Aug 2012 16:35:20 -0700 Subject: [rust-dev] Naming conventions for constructors Message-ID: <502AE0B8.103@mozilla.com> Hey. We need a consistent naming scheme for constructor functions. The current convention is to give these functions the same name as the type they create, so `core::dvec::dvec` is created by calling `core::dvec::dvec()`. We are in the process of changing our naming convention for types (as well as variants - which will eventually be types) to camel case. So very soon now your `Option` type will be created by calling `Some(foo)`, because `Some` is both a type and a constructor. Functions, on the other hand, will continue to have the lowercase + underscore convention. This leaves the question of what to call functions that are constructors. We could continue to name them after their types, but it's a little weird: fn DVec() -> DVec { ... } So now I need an alternate constructor. What do I call it? fn DVecWithParam(arg: foo) -> DVec{ ... } No other functions would follow such conventions. This is also harder to write reliable lint checks for. I'm disinclined to do this. Naming them after their type, but lowercase, is crummy in other ways: type DVec = ...; fn dvec() -> DVec { ... } Now to use DVec you're going to import two symbols: `import dvec::{DVec, dvec}`. All those dvecs ... so unsightly. This is mostly the scheme we will be left with after the conversion to camel case types, but I hope we can come up with something better before 0.4. One option: Constructors are called `new`, which will be freed up from the keyword list with the removal of classes. If there are multiple constructors in a module then they are descriptively disambiguated, as in `new_petunia` or `new_petunia_with_vase`. Most modules define one public type they are concerned with, so a simple `new` should suffice. The general pattern for defining a new 'object' would be: mod belt_buckle { struct BeltBuckle { ... } impl BeltBuckle { } fn new() -> BeltBuckle { ... } fn new_with_gold_plating(plating: GoldPlating) -> BeltBuckle { ... } } Then to use it: import my_crate::belt_buckle; let my_belt_buckle = belt_buckle::new(); You will mostly not import the constructor because it will need to be disambiguated from all the other 'new's in the world. Regards, Brian From hatahet at gmail.com Tue Aug 14 17:42:17 2012 From: hatahet at gmail.com (Ziad Hatahet) Date: Tue, 14 Aug 2012 17:42:17 -0700 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: <502AE0B8.103@mozilla.com> References: <502AE0B8.103@mozilla.com> Message-ID: This seems to be similar to the approach taken by Go, which seems simple and to the point. I presume taking it a step further and making new() be overloadable is out of the question? -- Ziad On Tue, Aug 14, 2012 at 4:35 PM, Brian Anderson wrote: > Hey. > > We need a consistent naming scheme for constructor functions. The current > convention is to give these functions the same name as the type they > create, so `core::dvec::dvec` is created by calling `core::dvec::dvec()`. > > We are in the process of changing our naming convention for types (as well > as variants - which will eventually be types) to camel case. So very soon > now your `Option` type will be created by calling `Some(foo)`, because > `Some` is both a type and a constructor. Functions, on the other hand, will > continue to have the lowercase + underscore convention. > > This leaves the question of what to call functions that are constructors. > We could continue to name them after their types, but it's a little weird: > > fn DVec() -> DVec { ... } > > So now I need an alternate constructor. What do I call it? > > fn DVecWithParam(arg: foo) -> DVec{ ... } > > No other functions would follow such conventions. This is also harder to > write reliable lint checks for. I'm disinclined to do this. > > Naming them after their type, but lowercase, is crummy in other ways: > > type DVec = ...; > > fn dvec() -> DVec { ... } > > Now to use DVec you're going to import two symbols: `import dvec::{DVec, > dvec}`. All those dvecs ... so unsightly. This is mostly the scheme we will > be left with after the conversion to camel case types, but I hope we can > come up with something better before 0.4. > > One option: > > Constructors are called `new`, which will be freed up from the keyword > list with the removal of classes. If there are multiple constructors in a > module then they are descriptively disambiguated, as in `new_petunia` or > `new_petunia_with_vase`. Most modules define one public type they are > concerned with, so a simple `new` should suffice. > > The general pattern for defining a new 'object' would be: > > mod belt_buckle { > > struct BeltBuckle { ... } > > impl BeltBuckle { > } > > fn new() -> BeltBuckle { ... } > > fn new_with_gold_plating(plating: GoldPlating) -> BeltBuckle { > ... > } > } > > Then to use it: > > import my_crate::belt_buckle; > > let my_belt_buckle = belt_buckle::new(); > > You will mostly not import the constructor because it will need to be > disambiguated from all the other 'new's in the world. > > Regards, > Brian > > ______________________________**_________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/**listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erick.tryzelaar at gmail.com Tue Aug 14 18:04:26 2012 From: erick.tryzelaar at gmail.com (Erick Tryzelaar) Date: Tue, 14 Aug 2012 18:04:26 -0700 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: <502AE0B8.103@mozilla.com> References: <502AE0B8.103@mozilla.com> Message-ID: On Tue, Aug 14, 2012 at 4:35 PM, Brian Anderson wrote: > Hey. Hello. :) > Then to use it: > > import my_crate::belt_buckle; > > let my_belt_buckle = belt_buckle::new(); > > You will mostly not import the constructor because it will need to be > disambiguated from all the other 'new's in the world. This is fine with me, I liked this style back in the pre-typeclass rust. There were two things that bugged me about this style. First, impls made import lines pretty dense, so it was nice to just import one type/impl/fn. Is this still the case with the new min/max classes? Second, If I wanted to import anything from the module, I'd have to write: import my_crate::belt_buckle; import my_crate::belt_buckle::BeltBuckle; Maybe we could add some sugar to combine those two lines into (forgive me if there's already a way to do this): import my_crate::belt_buckle::{., BeltBuckle}; From banderson at mozilla.com Tue Aug 14 18:24:05 2012 From: banderson at mozilla.com (Brian Anderson) Date: Tue, 14 Aug 2012 18:24:05 -0700 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: References: <502AE0B8.103@mozilla.com> Message-ID: <502AFA35.9000106@mozilla.com> On 08/14/2012 06:04 PM, Erick Tryzelaar wrote: > On Tue, Aug 14, 2012 at 4:35 PM, Brian Anderson wrote: >> Hey. > > Hello. > > :) > >> Then to use it: >> >> import my_crate::belt_buckle; >> >> let my_belt_buckle = belt_buckle::new(); >> >> You will mostly not import the constructor because it will need to be >> disambiguated from all the other 'new's in the world. > > > This is fine with me, I liked this style back in the pre-typeclass > rust. There were two things that bugged me about this style. First, > impls made import lines pretty dense, so it was nice to just import > one type/impl/fn. Is this still the case with the new min/max classes? The situation is much better with impls now. Any impls defined in the same module as the type are automatically available everywhere. The current scheme is nice in that you import `dvec::dvec` and get both the type and the constructor. > Second, If I wanted to import anything from the module, I'd have to > write: > > import my_crate::belt_buckle; > import my_crate::belt_buckle::BeltBuckle; > > > Maybe we could add some sugar to combine those two lines into (forgive > me if there's already a way to do this): > > import my_crate::belt_buckle::{., BeltBuckle}; > Something like this does seem appropriate. From garethdanielsmith at gmail.com Wed Aug 15 09:10:07 2012 From: garethdanielsmith at gmail.com (Gareth Smith) Date: Wed, 15 Aug 2012 17:10:07 +0100 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: <502AFA35.9000106@mozilla.com> References: <502AE0B8.103@mozilla.com> <502AFA35.9000106@mozilla.com> Message-ID: Hi, I guess this is also an issue when type names are used in non-constructor functions: e.g. should the to_str method actually be called to_Str, should to_bytes be called to_Bytes ? I think the "new" convention looks OK, but it is a bit weird with multiple constructors in a module because you then have to include the type name in the function name. I am curious what the motivation is for changing the naming convention of types? Thanks Gareth On 15 August 2012 02:24, Brian Anderson wrote: > On 08/14/2012 06:04 PM, Erick Tryzelaar wrote: > >> On Tue, Aug 14, 2012 at 4:35 PM, Brian Anderson >> wrote: >> >>> Hey. >>> >> >> Hello. >> >> :) >> >> Then to use it: >>> >>> import my_crate::belt_buckle; >>> >>> let my_belt_buckle = belt_buckle::new(); >>> >>> You will mostly not import the constructor because it will need to be >>> disambiguated from all the other 'new's in the world. >>> >> >> >> This is fine with me, I liked this style back in the pre-typeclass >> rust. There were two things that bugged me about this style. First, >> impls made import lines pretty dense, so it was nice to just import >> one type/impl/fn. Is this still the case with the new min/max classes? >> > > The situation is much better with impls now. Any impls defined in the same > module as the type are automatically available everywhere. The current > scheme is nice in that you import `dvec::dvec` and get both the type and > the constructor. > > > Second, If I wanted to import anything from the module, I'd have to >> write: >> >> import my_crate::belt_buckle; >> import my_crate::belt_buckle::**BeltBuckle; >> >> >> Maybe we could add some sugar to combine those two lines into (forgive >> me if there's already a way to do this): >> >> import my_crate::belt_buckle::{., BeltBuckle}; >> >> > Something like this does seem appropriate. > > > ______________________________**_________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/**listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From christian at siefkes.net Wed Aug 15 09:22:39 2012 From: christian at siefkes.net (Christian Siefkes) Date: Wed, 15 Aug 2012 18:22:39 +0200 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: (sfid-H20120815-181012-+050.14-1@spamfilter.osbf.lua) References: <502AE0B8.103@mozilla.com> <502AFA35.9000106@mozilla.com> (sfid-H20120815-181012-+050.14-1@spamfilter.osbf.lua) Message-ID: <502BCCCF.5030806@siefkes.net> On 08/15/2012 06:10 PM, Gareth Smith wrote: > I guess this is also an issue when type names are used in non-constructor > functions: e.g. should the to_str method actually be called to_Str, should > to_bytes be called to_Bytes ? why not camel-case everywhere, starting with a lower-case letter for functions and with a upper-case letter for types? Then these methods would become toStr, toBytes, matching the type names. I always find the convention to use underscores in some names and camel-case in others a bit unnatural and contrived. Also, on German and other keyboards, where typing _ requires the caps key, to_str is one keystroke more than toStr, which is a point of favor of camelCase. Best regards Christian -- |------- Dr. Christian Siefkes ------- christian at siefkes.net ------- | Homepage: http://www.siefkes.net/ | Blog: http://www.keimform.de/ | Peer Production Everywhere: http://peerconomy.org/wiki/ |---------------------------------- OpenPGP Key ID: 0x346452D8 -- Productivity ought to mean achieving more in an hour of work, but all to often it has come to mean extracting more for an hour of pay... managers dream of attaining new productivity levels through the simple mechanism of unpaid overtime. They divide whatever work is done in a week by forty hours, not by the eighty or ninety hours that a worker actually put in. That's not exactly productivity--it's more like fraud--but it's the state of the art for many American managers. -- Tom DeMarco and Timothy Lister, Peopleware -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 262 bytes Desc: OpenPGP digital signature URL: From banderson at mozilla.com Wed Aug 15 12:31:50 2012 From: banderson at mozilla.com (Brian Anderson) Date: Wed, 15 Aug 2012 12:31:50 -0700 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: References: <502AE0B8.103@mozilla.com> <502AFA35.9000106@mozilla.com> Message-ID: <502BF926.4000300@mozilla.com> On 08/15/2012 09:10 AM, Gareth Smith wrote: > Hi, > > I guess this is also an issue when type names are used in > non-constructor functions: e.g. should the to_str method actually be > called to_Str, should to_bytes be called to_Bytes ? > > I think the "new" convention looks OK, but it is a bit weird with > multiple constructors in a module because you then have to include the > type name in the function name. > > I am curious what the motivation is for changing the naming convention > of types? There are two reasons that I can recall off-hand. First, it adds some useful visual distinction. Rust code is anecdotally easier for humans to read under this scheme. Second, it helps to avoid an annoying problem with pattern matching, where in-scope variants cannot be used as bindings. enum foo { bar } let myfoo = bar; match myfoo { // I want to bind myfoo to variable bar, but bar must be // interpreted as a destructuring enum pattern bar => #debug("%?", bar), // this is a compile error }; // This is a more pronounced compile error. bar is a variant // so cannot be used a pattern (or let) binding. let bar = 0; This error doesn't show up too often, but when it does it's baffling and frustrating. From garethdanielsmith at gmail.com Wed Aug 15 13:13:00 2012 From: garethdanielsmith at gmail.com (Gareth Smith) Date: Wed, 15 Aug 2012 21:13:00 +0100 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: <502BF926.4000300@mozilla.com> References: <502AE0B8.103@mozilla.com> <502AFA35.9000106@mozilla.com> <502BF926.4000300@mozilla.com> Message-ID: <502C02CC.1030503@gmail.com> On 15/08/12 20:31, Brian Anderson wrote: > There are two reasons that I can recall off-hand... That sounds reasonable. Thanks. Gareth. From niko at alum.mit.edu Thu Aug 16 09:08:27 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 16 Aug 2012 09:08:27 -0700 Subject: [rust-dev] proposal: unify module/type namespaces Message-ID: <502D1AFB.2020904@alum.mit.edu> Currently modules and types occupy distinct namespaces. I propose that we merge them into one. The main reason to do this is that we can write something like: import foo::bar::MyType; ... let instance = MyType::new() where `new()` is a static fn (hereafter, selfless fn, because it is technically accurate but also mildly amusing). This resolves the constructor naming issue. It also changes how selfless fn names work: rather than floating out to the containing module, they would be contained within their type (which seems more natural). Coherence makes this well-defined; inherent selfless fns are associated with their inherent type, and selfless fns that fulfill a trait can be invoked via the trait version. Currently have a number of modules named after the primitive types, e.g., uint::max(). These can be rewritten as static functions. In fact, they probably *should* be static functions on some kind of `Number` or `Integer` trait anyhow. As a side benefit, we can make `uint`, `int`, and other primitive type names true keywords. It should be possible to import selfless fns as normal. With some more effort, we could also allow importing non-selfless fns?this would yield a function where the receiver is the first argument. This should help satisfy the desire expressed by various Haskell programmers to avoid dot notation. It would also sometimes be useful for higher-order functions. For example, `max()` can be defined as a method like so: trait Number { fn max(self, other: self) -> self; } and then used as follows: num_a.max(num_b) or as follows: import Number::max; ... max(num_a, num_b) whichever is more convenient or more aesthetically pleasing. Niko From ben.striegel at gmail.com Thu Aug 16 10:46:22 2012 From: ben.striegel at gmail.com (Benjamin Striegel) Date: Thu, 16 Aug 2012 13:46:22 -0400 Subject: [rust-dev] proposal: unify module/type namespaces In-Reply-To: <502D1AFB.2020904@alum.mit.edu> References: <502D1AFB.2020904@alum.mit.edu> Message-ID: > For example, `max()` can be defined as a method like so: > > trait Number { > fn max(self, other: self) -> self; > } > > and then used as follows: > > num_a.max(num_b) > > or as follows: > > import Number::max; > ... > max(num_a, num_b) > > whichever is more convenient or more aesthetically pleasing. Very excited at the prospect of this. The current system of defining a normal function and then defining a trait function that simply delegates to the normal function has always felt like needless boilerplate. Having the normal function be autogenerated from the trait function sounds like a dream come true. On Thu, Aug 16, 2012 at 12:08 PM, Niko Matsakis wrote: > Currently modules and types occupy distinct namespaces. I propose that we > merge them into one. The main reason to do this is that we can write > something like: > > import foo::bar::MyType; > ... > let instance = MyType::new() > > where `new()` is a static fn (hereafter, selfless fn, because it is > technically accurate but also mildly amusing). This resolves the > constructor naming issue. It also changes how selfless fn names work: > rather than floating out to the containing module, they would be contained > within their type (which seems more natural). Coherence makes this > well-defined; inherent selfless fns are associated with their inherent > type, and selfless fns that fulfill a trait can be invoked via the trait > version. > > Currently have a number of modules named after the primitive types, e.g., > uint::max(). These can be rewritten as static functions. In fact, they > probably *should* be static functions on some kind of `Number` or `Integer` > trait anyhow. As a side benefit, we can make `uint`, `int`, and other > primitive type names true keywords. > > It should be possible to import selfless fns as normal. With some more > effort, we could also allow importing non-selfless fns?this would yield a > function where the receiver is the first argument. This should help satisfy > the desire expressed by various Haskell programmers to avoid dot notation. > It would also sometimes be useful for higher-order functions. > > For example, `max()` can be defined as a method like so: > > trait Number { > fn max(self, other: self) -> self; > } > > and then used as follows: > > num_a.max(num_b) > > or as follows: > > import Number::max; > ... > max(num_a, num_b) > > whichever is more convenient or more aesthetically pleasing. > > > Niko > ______________________________**_________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/**listinfo/rust-dev > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ghexsel at gmail.com Thu Aug 16 11:20:59 2012 From: ghexsel at gmail.com (Gustavo Hexsel) Date: Thu, 16 Aug 2012 11:20:59 -0700 Subject: [rust-dev] proposal: unify module/type namespaces Message-ID: Sorry, I just lurk the mailing list once in a while. I just wanted to point that allowing multiple, slightly dissonant ways of calling the same function will inevitably lead to code style wars. Maybe one of them should be pointed as recommended, at least? []s Gus -------------- next part -------------- An HTML attachment was scrubbed... URL: From nejucomo at gmail.com Thu Aug 16 13:26:05 2012 From: nejucomo at gmail.com (Nathan) Date: Thu, 16 Aug 2012 13:26:05 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing Message-ID: Hello, I'm brand new to rust. I've read the tutorial once and not the manual. My first attempt at running "make" failed with a compiler error (I'll email or irc separately). I apologize if I'm re-covering ground or missing something, but I felt this general point was important to make as early as possible in a language's design. I hope I'm not too late. In another thread about naming conventions, it sounds as if there is a grammatical ambiguity which is resolved by scoping rules at compile time: match myfoo { bar => /* ... stuff ... */ } What does the left hand side of the match rule represent? IIUC, it is impossible to tell in rust without understanding what "bar" signifies in the surrounding scope. If there is an enum discriminator named "bar" and myfoo is of that type, then it means "match if myfoo is a bar value". On the other hand if this is not the case, it means "create a new binding called bar and bind it to the value in question". Is this true? If so, I suggest this is a serious problem which naming conventions will not solve. If it is not the case, please ignore this email and tell me to rtfm. ;-) So see why it is a problem, consider two use cases: a person learning the language, and a person auditing code for bugs. (For bonus material, see the post-script.) A person learning the language may learn only one semantic interpretation first, or may learn both but forget about one. They write code depending on the one semantic interpretation they are familiar with. It works. Then one day, there's a strange compiler error. Hopefully it's a very clear compiler error. That could save some time. Either way they probably need to revisit two different parts of language reference documentation to get a full understanding of the issue. Even if the "official documentation" has a single point that contrasts these two semantic possibilities, any 3rd party books, blogs, tutorials, etc... will reinforce the misunderstanding. Case two: A code auditor is looking for bugs, possibly subtle bugs or security flaws. They don't have a compiler. They're looking at a printout in an underground layer with no electronics allowed, or equivalently it's an interview question. Now, they see a pattern match rule where the left hand side is "bar". Even though the know the language perfectly, they cannot know the semantics here without understanding the scope of enum discriminators. Does this require looking at more than one file? If so, the problem complexity branches out indefinitely. They must do this for *every* such matching rule, even though many rules may be simple binding patterns rather than enum discriminators. See my last C example to illustrate the compound problems of grammar ambiguity *and* importing definitions from. If the imported definitions are not explicitly named in relation to where they are imported from, then an auditor must now read *every* file imported, and they must do this recursively. (Let's hope they have ide support.) If the imported names are explicitly associated with which source they are imported from, the auditor must recurse but at least it's linear instead of exponential. The solution I'm proposing is to alter the grammar so that it's possible by looking at only the pattern matching text, without knowing any other context whether it is a discriminator match or a new binding. There are at least two ways to do this: One is to ensure that it's always possible when looking at an identifier in *any* context whether or not it is a discriminator or a binding/reference. Haskell does this elegantly, IMO, by forcing discriminators to start with upper case and bindings/references to start with lower case. Any other rule that prevents the identifiers from overlapping is sufficient. I prefer this approach because it solves the ambiguity problem for *every* grammar production which involves either a reference/binding *or* an enum discriminator. Another is to change the specific match syntax so you say something like: match myfoo { discriminator bar => /* yes, this is a klunky new keyword, so I don't recommend this in practice, but it makes the point. */ bar => /* bare identifiers are always bindings. */ } -or- match myfoo { 'bar => /* This is just the same as the last, except we use a sigil instead of a keyword. It's compact. This could be considered an identifier disambiguation approach if all discriminator identifiers always begin with ' or some other sigil. */ bar => /* bare identifiers are always bindings. */ } -or- match myfoo { MyEnum.bar => /* Always require the type for discriminators, at least in this context. Klunky if other contexts do not require the type. Klunky since the type of myfoo is already specified. */ bar => /* bare identifiers are always bindings. */ } -or- match myfoo { bar => /* bare identifiers are always discriminators. */ let bar => /* bindings always use let (because it is similar to a let binding). kind of klunky and maybe confusing placement of the keyword. Plus nested patterns get klunky: */ [bar, let bar] => /* match a list/sequence/array thingy with a bar discriminator value and any other value which is bound to bar. Contrived but shows the grammar distinction in compound matches. */ } Anyway, please understand that those proposed syntaxes are just "ballpark" since I don't understand the grammar well, nor the style/community/taste. The main point is that grammars which are ambiguous without compile/run-time context are fraught with peril. Regards, Nathan Wilcox PS: Maybe a simpler way to state my desire is: Make it so that it's very hard to compete in an "underhanded backdoor" competition for rust and very easy to audit code for bugs. See for example this competition where entries look like correct C code to tally votes, but they surreptitiously skew the results in the favor of the author: http://graphics.stanford.edu/~danielrh/vote/scores.html When I am emperor, all language designers will be forced to audit all entries for all "underhanded backdoor" competitions for all other languages before they are allowed to design their language. ;-) (You may surmise that I was a security auditor in the past...) One of my favorites is here: http://graphics.stanford.edu/~danielrh/vote/mzalewski.c That entry is a case where examining a bit of text does not tell you its semantics because it may either be a variable reference *or* a macro instance and the only way to know is to have a mental model of the macros and variables in scope. If instead, all macro expansions required a $ prefix or whatever, there would be no ambiguity and the bug would be much easier to track down. PPS: Some other simple ambiguities in languages I kind of know off the top of my head which have lead to real world bugs I wrote or had to fix: javascript: x = 5; // ambiguity: Either reassign a declared binding in a containing scope, or create a new global binding. erlang: x = 5; // ambiguity: Either create a new binding called "x" referring to 5 *or* try to match the existing binding "x" to the value 5. C: #include "define_foo.h" static int bar = 42; int main(int argc, char** argv) { foo(bar); // Ambiguous, even without macros, depending on the contents of define_foo.h bar = 7; // Possibly invalid, depending on the contents of define_foo.h return bar; } Here are at least two possible contents for define_foo.h: int foo(int bar); -or- typedef char foo; From dteller at mozilla.com Thu Aug 16 13:33:51 2012 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Thu, 16 Aug 2012 22:33:51 +0200 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: <502D592F.1080605@mozilla.com> On 8/16/12 10:26 PM, Nathan wrote: > One is to ensure that it's always possible when looking at an > identifier in *any* context whether or not it is a discriminator or a > binding/reference. Haskell does this elegantly, IMO, by forcing > discriminators to start with upper case and bindings/references to > start with lower case. Any other rule that prevents the identifiers > from overlapping is sufficient. I prefer this approach because it > solves the ambiguity problem for *every* grammar production which > involves either a reference/binding *or* an enum discriminator. > > Another is to change the specific match syntax so you say something like: > > match myfoo { > discriminator bar => /* yes, this is a klunky new keyword, so I > don't recommend this in practice, but it makes the point. */ > bar => /* bare identifiers are always bindings. */ > } fwiw, OCaml does match myfoo with | #bar -> (*any item of sum type bar*) | `bar -> (*sum constructor `bar*) | bar -> (*binding*) It works nicely in practice. Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: OpenPGP digital signature URL: From pwalton at mozilla.com Thu Aug 16 13:44:27 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 16 Aug 2012 13:44:27 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: <502D5BAB.7030508@mozilla.com> On 8/16/12 1:26 PM, Nathan wrote: > The solution I'm proposing is to alter the grammar so that it's > possible by looking at only the pattern matching text, without knowing > any other context whether it is a discriminator match or a new > binding. There are at least two ways to do this: > > One is to ensure that it's always possible when looking at an > identifier in *any* context whether or not it is a discriminator or a > binding/reference. Haskell does this elegantly, IMO, by forcing > discriminators to start with upper case and bindings/references to > start with lower case. Any other rule that prevents the identifiers > from overlapping is sufficient. I prefer this approach because it > solves the ambiguity problem for *every* grammar production which > involves either a reference/binding *or* an enum discriminator. We used to require a ? before variable bindings, but it was very noisy in practice. It also caused bugs, because people would not write ? and things would sometimes compile. I'm personally very reluctant to go back to that world. I would like to try emitting a warning if the capitalization doesn't match up. (I'm actually OK with an error too, but we have so far avoided case sensitivity everywhere in the language and that's a nice property to have for e.g. interoperability with C code.) Patrick From pwalton at mozilla.com Thu Aug 16 13:51:46 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 16 Aug 2012 13:51:46 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: <502D592F.1080605@mozilla.com> References: <502D592F.1080605@mozilla.com> Message-ID: <502D5D62.4050509@mozilla.com> On 8/16/12 1:33 PM, David Rajchenbach-Teller wrote: > fwiw, OCaml does > > match myfoo with > | #bar -> (*any item of sum type bar*) > | `bar -> (*sum constructor `bar*) > | bar -> (*binding*) > > It works nicely in practice. But OCaml uses capitalization for sum types, like Haskell does. Also Niko points out that we can make a warning if you mention a variant in a pattern that would ordinarily be part of the type, but that variant wasn't imported. (For example: if you mention None in a pattern matching over option types, but None wasn't imported, you'd get a warning. Of course None gets imported by default, so this wouldn't actually occur.) Patrick From niko at alum.mit.edu Thu Aug 16 14:31:19 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 16 Aug 2012 14:31:19 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: <502D66A7.8010509@alum.mit.edu> We have discussed this point for some time, though I don't know if anyone raised the security review angle specifically before. I think there is a good case to be made that lint warnings adequately address this problem. You can set the mode to cause an error if case-distinctions are not observed in a pattern binding. Then a reviewer can be confident that, as long as the code compiles, nothing surprising is going on. Niko On 8/16/12 1:26 PM, Nathan wrote: > Hello, > > I'm brand new to rust. I've read the tutorial once and not the > manual. My first attempt at running "make" failed with a compiler > error (I'll email or irc separately). I apologize if I'm re-covering > ground or missing something, but I felt this general point was > important to make as early as possible in a language's design. I hope > I'm not too late. > > In another thread about naming conventions, it sounds as if there is a > grammatical ambiguity which is resolved by scoping rules at compile > time: > > match myfoo { > bar => /* ... stuff ... */ > } > > What does the left hand side of the match rule represent? IIUC, it is > impossible to tell in rust without understanding what "bar" signifies > in the surrounding scope. If there is an enum discriminator named > "bar" and myfoo is of that type, then it means "match if myfoo is a > bar value". On the other hand if this is not the case, it means > "create a new binding called bar and bind it to the value in > question". > > Is this true? > > If so, I suggest this is a serious problem which naming conventions > will not solve. If it is not the case, please ignore this email and > tell me to rtfm. ;-) > > So see why it is a problem, consider two use cases: a person learning > the language, and a person auditing code for bugs. (For bonus > material, see the post-script.) > > > A person learning the language may learn only one semantic > interpretation first, or may learn both but forget about one. They > write code depending on the one semantic interpretation they are > familiar with. It works. Then one day, there's a strange compiler > error. Hopefully it's a very clear compiler error. That could save > some time. Either way they probably need to revisit two different > parts of language reference documentation to get a full understanding > of the issue. Even if the "official documentation" has a single point > that contrasts these two semantic possibilities, any 3rd party books, > blogs, tutorials, etc... will reinforce the misunderstanding. > > > Case two: A code auditor is looking for bugs, possibly subtle bugs or > security flaws. They don't have a compiler. They're looking at a > printout in an underground layer with no electronics allowed, or > equivalently it's an interview question. > > Now, they see a pattern match rule where the left hand side is "bar". > Even though the know the language perfectly, they cannot know the > semantics here without understanding the scope of enum discriminators. > Does this require looking at more than one file? If so, the problem > complexity branches out indefinitely. They must do this for *every* > such matching rule, even though many rules may be simple binding > patterns rather than enum discriminators. > > See my last C example to illustrate the compound problems of grammar > ambiguity *and* importing definitions from. If the imported > definitions are not explicitly named in relation to where they are > imported from, then an auditor must now read *every* file imported, > and they must do this recursively. (Let's hope they have ide > support.) If the imported names are explicitly associated with which > source they are imported from, the auditor must recurse but at least > it's linear instead of exponential. > > > The solution I'm proposing is to alter the grammar so that it's > possible by looking at only the pattern matching text, without knowing > any other context whether it is a discriminator match or a new > binding. There are at least two ways to do this: > > One is to ensure that it's always possible when looking at an > identifier in *any* context whether or not it is a discriminator or a > binding/reference. Haskell does this elegantly, IMO, by forcing > discriminators to start with upper case and bindings/references to > start with lower case. Any other rule that prevents the identifiers > from overlapping is sufficient. I prefer this approach because it > solves the ambiguity problem for *every* grammar production which > involves either a reference/binding *or* an enum discriminator. > > Another is to change the specific match syntax so you say something like: > > match myfoo { > discriminator bar => /* yes, this is a klunky new keyword, so I > don't recommend this in practice, but it makes the point. */ > bar => /* bare identifiers are always bindings. */ > } > > -or- > > match myfoo { > 'bar => /* This is just the same as the last, except we use a sigil > instead of a keyword. It's compact. This could be considered an > identifier disambiguation approach if all discriminator identifiers > always begin with ' or some other sigil. */ > bar => /* bare identifiers are always bindings. */ > } > > -or- > > match myfoo { > MyEnum.bar => /* Always require the type for discriminators, at > least in this context. Klunky if other contexts do not require the > type. Klunky since the type of myfoo is already specified. */ > bar => /* bare identifiers are always bindings. */ > } > > -or- > > match myfoo { > bar => /* bare identifiers are always discriminators. */ > let bar => /* bindings always use let (because it is similar to a > let binding). kind of klunky and maybe confusing placement of the > keyword. Plus nested patterns get klunky: */ > [bar, let bar] => /* match a list/sequence/array thingy with a bar > discriminator value and any other value which is bound to bar. > Contrived but shows the grammar distinction in compound matches. */ > } > > > > Anyway, please understand that those proposed syntaxes are just > "ballpark" since I don't understand the grammar well, nor the > style/community/taste. The main point is that grammars which are > ambiguous without compile/run-time context are fraught with peril. > > > Regards, > Nathan Wilcox > > > PS: > > Maybe a simpler way to state my desire is: Make it so that it's very > hard to compete in an "underhanded backdoor" competition for rust and > very easy to audit code for bugs. > > See for example this competition where entries look like correct C > code to tally votes, but they surreptitiously skew the results in the > favor of the author: > http://graphics.stanford.edu/~danielrh/vote/scores.html > > When I am emperor, all language designers will be forced to audit all > entries for all "underhanded backdoor" competitions for all other > languages before they are allowed to design their language. ;-) (You > may surmise that I was a security auditor in the past...) > > One of my favorites is here: > http://graphics.stanford.edu/~danielrh/vote/mzalewski.c > > That entry is a case where examining a bit of text does not tell you > its semantics because it may either be a variable reference *or* a > macro instance and the only way to know is to have a mental model of > the macros and variables in scope. If instead, all macro expansions > required a $ prefix or whatever, there would be no ambiguity and the > bug would be much easier to track down. > > > PPS: > > Some other simple ambiguities in languages I kind of know off the top > of my head which have lead to real world bugs I wrote or had to fix: > > javascript: > x = 5; // ambiguity: Either reassign a declared binding in a > containing scope, or create a new global binding. > > erlang: > x = 5; // ambiguity: Either create a new binding called "x" referring > to 5 *or* try to match the existing binding "x" to the value 5. > > C: > #include "define_foo.h" > > static int bar = 42; > > int main(int argc, char** argv) { > foo(bar); // Ambiguous, even without macros, depending on the > contents of define_foo.h > bar = 7; // Possibly invalid, depending on the contents of define_foo.h > return bar; > } > > Here are at least two possible contents for define_foo.h: > int foo(int bar); > > -or- > > typedef char foo; > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From banderson at mozilla.com Thu Aug 16 15:03:15 2012 From: banderson at mozilla.com (Brian Anderson) Date: Thu, 16 Aug 2012 15:03:15 -0700 Subject: [rust-dev] Naming conventions for constructors In-Reply-To: <502AE0B8.103@mozilla.com> References: <502AE0B8.103@mozilla.com> Message-ID: <502D6E23.3070505@mozilla.com> On 08/14/2012 04:35 PM, Brian Anderson wrote: > Hey. > > We need a consistent naming scheme for constructor functions. The > current convention is to give these functions the same name as the type > they create, so `core::dvec::dvec` is created by calling > `core::dvec::dvec()`. > > We are in the process of changing our naming convention for types (as > well as variants - which will eventually be types) to camel case. So > very soon now your `Option` type will be created by calling `Some(foo)`, > because `Some` is both a type and a constructor. Functions, on the other > hand, will continue to have the lowercase + underscore convention. > > This leaves the question of what to call functions that are > constructors. We could continue to name them after their types, but it's > a little weird: > > fn DVec() -> DVec { ... } > > So now I need an alternate constructor. What do I call it? > > fn DVecWithParam(arg: foo) -> DVec{ ... } > Niko has convinced me that, under the current namespace rules, sticking with the current naming scheme of using the type name is best because this is the way that imports work out nicest: import belt_buckle::BeltBuckle; // give me the type and constructor If we do merge the type and module namespaces, then you can still just import the type as above and construct it with `BeltBuckle::new()`. My plan for now is to finish the camel casing of types, then go back through and find all the constructors and convert them. Then I will hope that we do the namespace merging so we can revisit the constructor issue again. If that's acceptable, then the remaining question is of what to do with secondary constructors. I will punt on that for now because it doesn't show up much in existing library code. From pwalton at mozilla.com Thu Aug 16 15:13:41 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 16 Aug 2012 15:13:41 -0700 Subject: [rust-dev] proposal: unify module/type namespaces In-Reply-To: <502D1AFB.2020904@alum.mit.edu> References: <502D1AFB.2020904@alum.mit.edu> Message-ID: <502D7095.9090500@mozilla.com> I'm tentatively in favor of this proposal. Might be a good idea to hold off on the dot notation switch though. I also wonder if one should have to explicitly import trait methods as well. To make Niko's proposal clearer: here's how one would define the MyType: mod foo { mod bar { struct MyType { ... } impl MyType { fn new() -> MyType { MyType { ... } } } } } Patrick From niko at alum.mit.edu Thu Aug 16 15:40:06 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 16 Aug 2012 15:40:06 -0700 Subject: [rust-dev] proposal: unify module/type namespaces In-Reply-To: <502D7095.9090500@mozilla.com> References: <502D1AFB.2020904@alum.mit.edu> <502D7095.9090500@mozilla.com> Message-ID: <502D76C6.3040104@alum.mit.edu> On 8/16/12 3:13 PM, Patrick Walton wrote: > Might be a good idea to hold off on the dot notation switch though. To be clear: I did not propose removing dot notation or changing it in any way. I just said that if we did merge type/module namespaces, it opens the door to being able to import "methods" and use them as normal functions. Niko From nejucomo at gmail.com Thu Aug 16 18:10:39 2012 From: nejucomo at gmail.com (Nathan) Date: Thu, 16 Aug 2012 18:10:39 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: <502D66A7.8010509@alum.mit.edu> References: <502D66A7.8010509@alum.mit.edu> Message-ID: I caught up a little on the state of this topic in IRC, and now I see it's an old topic. I don't want to rub old callouses, but I do hope my use cases are motivating. On Thu, Aug 16, 2012 at 2:31 PM, Niko Matsakis wrote: > We have discussed this point for some time, though I don't know if anyone > raised the security review angle specifically before. > > I think there is a good case to be made that lint warnings adequately > address this problem. > I almost feel like a lint warning which can be disabled is worse. Instead of a "soft" convention, we have a "checked" convention, so violations of the convention are even more surprising. One of my proposed use cases was a reviewer on a desert island with a paper print out. That was a bit of shorthand, but that's intended to cover book publications, diff hunks, github source listings, presentation slides, mailing list patch posts, etc... My argument was specifically about an auditor who does not have access to an automated tool. In a non-ambiguous grammar case, this is no real disadvantage at least for knowing how to interpret a snippet. But if the solution is you must run an automated static tool, you lose the benefit of analysis in all those peripheral use cases. I'd argue that a default-on lint check for a convention makes violations of that convention even more surprising. Newbies learning the language have the violation negatively reinforced as "not probable", but it's much easier to have one big "not possible" mental stamp instead of a long list of fine grained, rarely used "not probable except when rare thing X happens" facts. In the world with the default-on lint check, I suspect it'd be easier to submit a patch that contains a backdoor-in-plain sight, because people's plain sight has been trained with blinders. > You can set the mode to cause an error if > case-distinctions are not observed in a pattern binding. Then a reviewer can > be confident that, as long as the code compiles, nothing surprising is going > on. > A lint check that's on by default is a good 80% solution so long as we consider the maxim "with enough eyes, all bugs are shallow" really means "automated tools" for "eyes". That's practical, because any sane patch review process will compile and run some tests before merging. I still say only 80%, because of all the "human without tools" scenarios, such as everyone on the mailing list who sees the patch but doesn't apply it and run lint themselves. It's hard to say how valuable those other cases are. They might capture a long tail of valuable contributions to open source or maybe they have little impact. The backdoor case is compelling to me, but I'm probably overly paranoid. I hope I am, at least. ;-) I'm happy with an 80% solution that the community easily accepts versus a 100% solution that is rejected. > > > Niko > > Nathan > On 8/16/12 1:26 PM, Nathan wrote: >> >> Hello, >> >> I'm brand new to rust. I've read the tutorial once and not the >> manual. My first attempt at running "make" failed with a compiler >> error (I'll email or irc separately). I apologize if I'm re-covering >> ground or missing something, but I felt this general point was >> important to make as early as possible in a language's design. I hope >> I'm not too late. >> >> In another thread about naming conventions, it sounds as if there is a >> grammatical ambiguity which is resolved by scoping rules at compile >> time: >> >> match myfoo { >> bar => /* ... stuff ... */ >> } >> >> What does the left hand side of the match rule represent? IIUC, it is >> impossible to tell in rust without understanding what "bar" signifies >> in the surrounding scope. If there is an enum discriminator named >> "bar" and myfoo is of that type, then it means "match if myfoo is a >> bar value". On the other hand if this is not the case, it means >> "create a new binding called bar and bind it to the value in >> question". >> >> Is this true? >> >> If so, I suggest this is a serious problem which naming conventions >> will not solve. If it is not the case, please ignore this email and >> tell me to rtfm. ;-) >> >> So see why it is a problem, consider two use cases: a person learning >> the language, and a person auditing code for bugs. (For bonus >> material, see the post-script.) >> >> >> A person learning the language may learn only one semantic >> interpretation first, or may learn both but forget about one. They >> write code depending on the one semantic interpretation they are >> familiar with. It works. Then one day, there's a strange compiler >> error. Hopefully it's a very clear compiler error. That could save >> some time. Either way they probably need to revisit two different >> parts of language reference documentation to get a full understanding >> of the issue. Even if the "official documentation" has a single point >> that contrasts these two semantic possibilities, any 3rd party books, >> blogs, tutorials, etc... will reinforce the misunderstanding. >> >> >> Case two: A code auditor is looking for bugs, possibly subtle bugs or >> security flaws. They don't have a compiler. They're looking at a >> printout in an underground layer with no electronics allowed, or >> equivalently it's an interview question. >> >> Now, they see a pattern match rule where the left hand side is "bar". >> Even though the know the language perfectly, they cannot know the >> semantics here without understanding the scope of enum discriminators. >> Does this require looking at more than one file? If so, the problem >> complexity branches out indefinitely. They must do this for *every* >> such matching rule, even though many rules may be simple binding >> patterns rather than enum discriminators. >> >> See my last C example to illustrate the compound problems of grammar >> ambiguity *and* importing definitions from. If the imported >> definitions are not explicitly named in relation to where they are >> imported from, then an auditor must now read *every* file imported, >> and they must do this recursively. (Let's hope they have ide >> support.) If the imported names are explicitly associated with which >> source they are imported from, the auditor must recurse but at least >> it's linear instead of exponential. >> >> >> The solution I'm proposing is to alter the grammar so that it's >> possible by looking at only the pattern matching text, without knowing >> any other context whether it is a discriminator match or a new >> binding. There are at least two ways to do this: >> >> One is to ensure that it's always possible when looking at an >> identifier in *any* context whether or not it is a discriminator or a >> binding/reference. Haskell does this elegantly, IMO, by forcing >> discriminators to start with upper case and bindings/references to >> start with lower case. Any other rule that prevents the identifiers >> from overlapping is sufficient. I prefer this approach because it >> solves the ambiguity problem for *every* grammar production which >> involves either a reference/binding *or* an enum discriminator. >> >> Another is to change the specific match syntax so you say something like: >> >> match myfoo { >> discriminator bar => /* yes, this is a klunky new keyword, so I >> don't recommend this in practice, but it makes the point. */ >> bar => /* bare identifiers are always bindings. */ >> } >> >> -or- >> >> match myfoo { >> 'bar => /* This is just the same as the last, except we use a sigil >> instead of a keyword. It's compact. This could be considered an >> identifier disambiguation approach if all discriminator identifiers >> always begin with ' or some other sigil. */ >> bar => /* bare identifiers are always bindings. */ >> } >> >> -or- >> >> match myfoo { >> MyEnum.bar => /* Always require the type for discriminators, at >> least in this context. Klunky if other contexts do not require the >> type. Klunky since the type of myfoo is already specified. */ >> bar => /* bare identifiers are always bindings. */ >> } >> >> -or- >> >> match myfoo { >> bar => /* bare identifiers are always discriminators. */ >> let bar => /* bindings always use let (because it is similar to a >> let binding). kind of klunky and maybe confusing placement of the >> keyword. Plus nested patterns get klunky: */ >> [bar, let bar] => /* match a list/sequence/array thingy with a bar >> discriminator value and any other value which is bound to bar. >> Contrived but shows the grammar distinction in compound matches. */ >> } >> >> >> >> Anyway, please understand that those proposed syntaxes are just >> "ballpark" since I don't understand the grammar well, nor the >> style/community/taste. The main point is that grammars which are >> ambiguous without compile/run-time context are fraught with peril. >> >> >> Regards, >> Nathan Wilcox >> >> >> PS: >> >> Maybe a simpler way to state my desire is: Make it so that it's very >> hard to compete in an "underhanded backdoor" competition for rust and >> very easy to audit code for bugs. >> >> See for example this competition where entries look like correct C >> code to tally votes, but they surreptitiously skew the results in the >> favor of the author: >> http://graphics.stanford.edu/~danielrh/vote/scores.html >> >> When I am emperor, all language designers will be forced to audit all >> entries for all "underhanded backdoor" competitions for all other >> languages before they are allowed to design their language. ;-) (You >> may surmise that I was a security auditor in the past...) >> >> One of my favorites is here: >> http://graphics.stanford.edu/~danielrh/vote/mzalewski.c >> >> That entry is a case where examining a bit of text does not tell you >> its semantics because it may either be a variable reference *or* a >> macro instance and the only way to know is to have a mental model of >> the macros and variables in scope. If instead, all macro expansions >> required a $ prefix or whatever, there would be no ambiguity and the >> bug would be much easier to track down. >> >> >> PPS: >> >> Some other simple ambiguities in languages I kind of know off the top >> of my head which have lead to real world bugs I wrote or had to fix: >> >> javascript: >> x = 5; // ambiguity: Either reassign a declared binding in a >> containing scope, or create a new global binding. >> >> erlang: >> x = 5; // ambiguity: Either create a new binding called "x" referring >> to 5 *or* try to match the existing binding "x" to the value 5. >> >> C: >> #include "define_foo.h" >> >> static int bar = 42; >> >> int main(int argc, char** argv) { >> foo(bar); // Ambiguous, even without macros, depending on the >> contents of define_foo.h >> bar = 7; // Possibly invalid, depending on the contents of define_foo.h >> return bar; >> } >> >> Here are at least two possible contents for define_foo.h: >> int foo(int bar); >> >> -or- >> >> typedef char foo; >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev at mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev > > From dteller at mozilla.com Thu Aug 16 14:16:20 2012 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Thu, 16 Aug 2012 23:16:20 +0200 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: <502D5D62.4050509@mozilla.com> References: <502D592F.1080605@mozilla.com> <502D5D62.4050509@mozilla.com> Message-ID: <502D6324.8030602@mozilla.com> On 8/16/12 10:51 PM, Patrick Walton wrote: > On 8/16/12 1:33 PM, David Rajchenbach-Teller wrote: >> fwiw, OCaml does >> >> match myfoo with >> | #bar -> (*any item of sum type bar*) >> | `bar -> (*sum constructor `bar*) >> | bar -> (*binding*) >> >> It works nicely in practice. > > But OCaml uses capitalization for sum types, like Haskell does. Actually, not for open sum types, in which cases OCaml uses ` (backtick) instead. But this doesn't change anything to the argument > Also Niko points out that we can make a warning if you mention a variant > in a pattern that would ordinarily be part of the type, but that variant > wasn't imported. (For example: if you mention None in a pattern matching > over option types, but None wasn't imported, you'd get a warning. Of > course None gets imported by default, so this wouldn't actually occur.) Not sure how that would work out in practice. Btw, in Opa, we used to have lots of bugs caused by this kind of ambiguity (and a purely structural type system), so I believe this is worth spending some time ironing out. Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: OpenPGP digital signature URL: From pwalton at mozilla.com Thu Aug 16 22:11:48 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Thu, 16 Aug 2012 22:11:48 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: <502D6324.8030602@mozilla.com> References: <502D592F.1080605@mozilla.com> <502D5D62.4050509@mozilla.com> <502D6324.8030602@mozilla.com> Message-ID: <502DD294.4090800@mozilla.com> On 08/16/2012 02:16 PM, David Rajchenbach-Teller wrote: > Not sure how that would work out in practice. > > Btw, in Opa, we used to have lots of bugs caused by this kind of > ambiguity (and a purely structural type system), so I believe this is > worth spending some time ironing out. I think it's worth trying the warning. We tried sigils both on the variables (prefix '?') and on nullary variants (postfix '.') and both had bad ergonomics. As I said earlier, I really don't want to go back to that world. Patrick From peterhull90 at gmail.com Fri Aug 17 01:32:46 2012 From: peterhull90 at gmail.com (Peter Hull) Date: Fri, 17 Aug 2012 09:32:46 +0100 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: Just for my benefit, in Nathan's example: > > match myfoo { > bar => /* ... stuff ... */ > } > where bar is not an enum, is bar now an exact synonym for myfoo? If so, maybe the compiler could warn that you probably didn't want to do such a simple 1:1 binding? And maybe if you did want this binding, you could suppress the warning by putting (bar), which is reminiscent of a 1-element tuple, otherwise disallowed. Pete From nejucomo at gmail.com Fri Aug 17 10:25:52 2012 From: nejucomo at gmail.com (Nathan) Date: Fri, 17 Aug 2012 10:25:52 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: On Fri, Aug 17, 2012 at 1:32 AM, Peter Hull wrote: > Just for my benefit, in Nathan's example: >> >> match myfoo { >> bar => /* ... stuff ... */ >> } >> > where bar is not an enum, is bar now an exact synonym for myfoo? > > If so, maybe the compiler could warn that you probably didn't want to > do such a simple 1:1 binding? And maybe if you did want this binding, > you could suppress the warning by putting (bar), which is reminiscent > of a 1-element tuple, otherwise disallowed. > Yes, this is true, but it doesn't address the general problem: match myfoo { [bar, 42] => /* ... */ } I may have the rust syntax wrong, but the point is anywhere in a structured/compound pattern either a variable binding or an enum discriminator may appear, right? > Pete Nathan > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From banderson at mozilla.com Fri Aug 17 11:39:04 2012 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 17 Aug 2012 11:39:04 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: <502E8FC8.8060106@mozilla.com> On 08/17/2012 01:32 AM, Peter Hull wrote: > Just for my benefit, in Nathan's example: >> >> match myfoo { >> bar => /* ... stuff ... */ >> } >> > where bar is not an enum, is bar now an exact synonym for myfoo? Yes. > > If so, maybe the compiler could warn that you probably didn't want to > do such a simple 1:1 binding? And maybe if you did want this binding, > you could suppress the warning by putting (bar), which is reminiscent > of a 1-element tuple, otherwise disallowed. > This would be a useful warning, though perhaps some of the other suggested warnings would also catch this error. From graydon at mozilla.com Fri Aug 17 12:15:22 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Fri, 17 Aug 2012 12:15:22 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: Message-ID: <502E984A.6000302@mozilla.com> On 12-08-17 10:25 AM, Nathan wrote: > Yes, this is true, but it doesn't address the general problem: > > match myfoo { > [bar, 42] => /* ... */ > } > > I may have the rust syntax wrong, but the point is anywhere in a > structured/compound pattern either a variable binding or an enum > discriminator may appear, right? Yes. Or a constant. I.e. 'some(red)' doesn't match 'some(blue)' if red and blue are named constant integers (or enum tags). I think it's going to be a bit of a losing battle to differentiate these in all cases; you wind up having to make one or more "very frequently written thing" either very ugly or likely to be misused. Now, curiously, this is not as frequently _ambiguous_ as it seems. Most cases are automatically unambiguous: - foo::bar => ... is unambiguous due to '::' - foo(_) => ... is unambiguous due to '(_)' - ref foo => ... is unambiguous due to 'ref' - copy foo => ... is unambiguous due to 'copy' The only case we're actually looking at is nullary-constructor or equality-with-a-constant. That is, someone writing: match ... { nonr => ... } and matching 'some(x)' against it because they fat-fingered 'none' and wound up binding an identifier (or alternatively, they mentioned an ident they thought was a constructor-in-scope but it was not, so they introduced a binding). Fixing this is Hard though. We struggled a lot. You have this sequence of painful logic: - Hard requirement: 'let x = 10' declares a variable. - Hard requirement: 'const x : int = 10' declares a constant. - Hard requirement: 'x' in expression position refers to a variable and/or a constant, at least. These are very basic "if we change them, the language passes the threshold of too-ugly-to-write". So they're not on the table. Now consider: - Misuse avoidance #1: users tend to forget that patterns and exprs are different, since they "look similar", so anything they write as an expr they're likely to write as a pattern. In particular, 'x' as a constant (and 'x' as a nullary enum ctor, if those are unadorned). - Misuse avoidance #2: users tend to write all enum ctors the same way, nullary and non, so if 'none' has a sigil, 'some' has to have one too, otherwise they'll wind up writing 'none'-without-the-sigil just out of symmetry with 'some'. - Ergonomics #1: ideally the distinction between a constant integer like "const red : int = 0xff0000;" and an enum ctor can be forgotten by users. People change between magic constants and enums with some frequency when writing code. - Ergonomics #2: ideally enum ctors don't all have sigils in expr position, since a great many are unambiguously ctor-calls anyway (eg. 'some(10)' is much nicer than '`some(10)' everywhere). Misuse avoidance #1 makes it pretty much impossible to dodge the constant-vs-binding ambiguity, and the combination of #1 and #2 second means that the only dodge likely to work on the enum-vs-binding ambiguity is one where _all_ occurrences of _all_ ctors require sigils (eg. the Ocaml `Variant thing, for nullary and N>1-ary, in pattern and expr forms alike). This is possible. But it's about the only solution I can see that doesn't bring more problems than it solves. And even if we did that, it wouldn't solve #1, and would lose ergonomic arguments #1 and #2. So, with all this in mind, we went with the SML rule: having the compiler restrict names introduced-by-a-pattern to not-collide with any in-scope nullary ctors and constants. It _seems_ to be working pretty well in practice. -Graydon From nejucomo at gmail.com Fri Aug 17 12:56:42 2012 From: nejucomo at gmail.com (Nathan) Date: Fri, 17 Aug 2012 12:56:42 -0700 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: <502E984A.6000302@mozilla.com> References: <502E984A.6000302@mozilla.com> Message-ID: On Fri, Aug 17, 2012 at 12:15 PM, Graydon Hoare wrote: > [Snipped everything except what I respond to...] > So, with all this in mind, we went with the SML rule: having the compiler > restrict names introduced-by-a-pattern to not-collide with any in-scope > nullary ctors and constants. It _seems_ to be working pretty well in > practice. Thanks for describing the design trade-offs very well. I'll try to be less vocal, especially if what we have works in practice. One other thought, however: The case where ctors and variable references may both appear in expressions is unambiguous, because in each case the identifier represents a value. Here I'm thinking a ctor named "foo" is indistinguishable from a reference named "foo" that happens to refer to an enum value. I started to wonder if there could be a symmetric consistency in pattern matching. Something with the semantics: "If the value-to-be-matched is equal/identical to the value referred to by identifier "foo", then the match proceeds successfully." In that case, whatever syntax has those semantics could be used both with ctors and with variables. I'll try yet another mangling of the grammar: let's suppose EQUALITY_PATTERN ::= '=' IDENTIFIER in patterns, so: match myfoo { =bar => /* match on equality */ quz => /* bind "quz" to anything */ } Yes, that syntax is horrible. The point is: it doesn't matter if "bar" refers to a nullary enum ctor *or* a reference, the semantics are the same. I suppose explicitly marking binding patterns and un-marked identifiers always mean "match by equality without binding", then there would be the same expression versus pattern symmetry for nullary ctors and any other reference. This was what the abandoned '?' sigil accomplished, right? It was for creating a new binding on match? I'm starting to like that abandoned approach. Ok, I'm going to bite my tongue until I have a lot more context, such as experience writing a bunch of rust code, and a better understanding of the community and direction. I hope I haven't stepped on any toes. > > -Graydon > Nathan > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From nadavvin at gmail.com Sat Aug 18 05:21:29 2012 From: nadavvin at gmail.com (Nadav Vinik) Date: Sat, 18 Aug 2012 15:21:29 +0300 Subject: [rust-dev] error: unresolved name: each Message-ID: for each loop don't work in 3.0 and trunk: for each(~[2, 4, 8, 5, 16]) |n| { if n % 2 != 0 { println(~"found odd number!"); break; } } http://dl.rust-lang.org/doc/tutorial.html#for-loops also it is possible to get the value from this loop: import io::println; fn main() { for 5.times { println("Here's some Rust!"); } } for example: for 5.times |i|{ println(i+"Here's some Rust!"); } Thanks Nadav -------------- next part -------------- An HTML attachment was scrubbed... URL: From niko at alum.mit.edu Mon Aug 20 10:40:32 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Mon, 20 Aug 2012 10:40:32 -0700 Subject: [rust-dev] error: unresolved name: each In-Reply-To: References: Message-ID: <50327690.5080608@alum.mit.edu> On 8/18/12 5:21 AM, Nadav Vinik wrote: > for each loop don't work in 3.0 and trunk: > > for each(~[2,4,8,5,16]) |n| { > if n %2 !=0 { > println(~"found odd number!"); > break; > } > } What's missing here is a import vec::each; however this would be more idiomatically written as for the_vector.each |n| { ... } > also it is possible to get the value from this loop: > import io::println; > > fn main() { > for 5.times { > println("Here's some Rust!"); > } > } The preferred way (at least, my preferred way) is to use `uint::range` or `int::range`, depending on whether you want unsigned or signed integers. For example: for uint::range(0, 5) |i| { ... } This may change as we revamp our APIs. At minimum, the `uint` prefix will probably go away and range will be replaced by a generic function that can iterate over any "integer-like" thing. Niko From lindsey at rockstargirl.org Mon Aug 20 17:01:01 2012 From: lindsey at rockstargirl.org (Lindsey Kuper) Date: Mon, 20 Aug 2012 17:01:01 -0700 Subject: [rust-dev] Typeclasses turn trait-er: status update Message-ID: Hi everyone, I thought I'd post a progress report on traits in Rust. For a high-level overview of what traits are and where Rust is headed with them, I'll quote from the development roadmap [0]: Traits are interfaces that carry method implementations and requirements on the self-type; they can be used to achieve code reuse without introducing much of the pain that comes from conventional inheritance: they can be mixed in any order, can be declared independent from the type they affect, and are compiled independently for each type that implements them (indeed, will inline and specialize exactly as any other method will). This work will replace the iface keyword with trait and provide (hopefully) most of what people miss when writing rust in OO style. The "method implementations ... on the self-type" mentioned in that description are the "default methods" that I described in my talk a week and a half ago [1]. They're also called "provided methods" in the traits literature, whereas method signatures like the ones Rust has had in ifaces all along are called "required methods". I use the terms "default method" and "provided method" interchangeably. In the talk, I said that I was going to try to get default methods working by the time I left. Since my internship ended on Friday, you might be wondering: did I manage to do that? Sort of! As of last week, trivial default methods work; for instance, you can write: trait Cat { fn meow() -> bool; fn scratch() -> bool; fn purr() -> bool { true } // a default method } impl int : Cat { fn meow() -> bool { self.scratch() } fn scratch() -> bool { self.purr() } // notice that we don't have to implement purr } fn main() { assert 5.meow(); } (For comparison, the equivalent Haskell would be something like https://gist.github.com/3346078 .) For default methods to actually be useful, though, we have to be able to use "self" in them. For instance, in the example I gave in my talk of an Eq typeclass with a provided method `isNotEq`, we want the body of `isNotEq` to be something like `!self.isEq(a)`. This is still not working in Rust. Right now, methods that make self-calls raise an "unimplemented type_of: ty_self" ICE in trans. (In the specific case of Eq, there's an additional issue to confront, because the provided method also takes an argument of type self, and right now the typechecker is unhappy with provided methods that take or return arguments of type self; that will also need to be fixed.) So, as of today, it is hard to write code with nontrivial default methods. But it should not be terribly difficult to fix, and I'll be working on it later this week. Now that default methods are beginning to work, it is becoming more clear that certain patches of awkward code in the compiler are awkward because they are workarounds for a lack of default methods. It would be useful to keep track of those so that we can more easily fix them up once default methods are fully working. So, if you see one, you can help by opening an issue, adding a FIXME in the code tagged with the issue, and marking the issue as blocked on issue #2794 (and thanks to everyone who has already started to do this). Finally, as of Friday, the "iface" keyword no longer parses; it's all "trait" all the time, now. Cheers, Lindsey [0]: https://github.com/mozilla/rust/wiki/Note-development-roadmap, "Extend interfaces to full traits" under "OO-system changes" [1]: https://air.mozilla.org/rust-typeclasses/ From dteller at mozilla.com Tue Aug 21 03:26:48 2012 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Tue, 21 Aug 2012 12:26:48 +0200 Subject: [rust-dev] Typeclasses turn trait-er: status update In-Reply-To: References: Message-ID: <50336268.3030504@mozilla.com> That looks really cool. Cheers, David -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: OpenPGP digital signature URL: From dteller at mozilla.com Tue Aug 21 05:40:42 2012 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Tue, 21 Aug 2012 14:40:42 +0200 Subject: [rust-dev] Student projects Message-ID: <503381CA.80609@mozilla.com> Dear Rusties, As mentioned a few months ago, I would like to suggest some Rust-related project topics to a few Master-level students. I have no clear idea of their actual level of motivation and skill (this is the first year we work with this department), but it would be great if we could have a few non-critical projects to offer them. So, any libraries that need some loving? Any refactorings required to the code? Projects start early November, end mid-February and students are only expected to spend a few hours per week working on the projects. Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: OpenPGP digital signature URL: From banderson at mozilla.com Tue Aug 21 12:55:44 2012 From: banderson at mozilla.com (Brian Anderson) Date: Tue, 21 Aug 2012 12:55:44 -0700 Subject: [rust-dev] Student projects In-Reply-To: <503381CA.80609@mozilla.com> References: <503381CA.80609@mozilla.com> Message-ID: <5033E7C0.9080401@mozilla.com> On 08/21/2012 05:40 AM, David Rajchenbach-Teller wrote: > Dear Rusties, > > As mentioned a few months ago, I would like to suggest some > Rust-related project topics to a few Master-level students. I have no > clear idea of their actual level of motivation and skill (this is the > first year we work with this department), but it would be great if we > could have a few non-critical projects to offer them. > > So, any libraries that need some loving? Any refactorings required to > the code? > Here are some ideas. Servo is probably a fertile area for contributing to Rust since there are seemingly so many things that will eventually be needed, but so far we've not been successful at enumerating them. Core Rust stuff: * Move bindgen into the rust repo and implement a bindgen pass (automatically generate C bindings). Involves some unsavory hacking on the build system. * Extract the metadata module from rustc and use it to implement type safe dynamic library loading. * Convert shape code (logging, cycle collection) to visitor code. Probably not fun. * Get rustc working with the LLVM MC-JIT, with the intent of implementing a REPL. Several people have poked at this without making much progress * Improve the performance of #fmt. Could involve creating a string builder. Servo-related things: * PNG, JPG decoders - servo is using native code currently. * Add an LRU-SP cache - https://github.com/mozilla/servo/issues/51 * HTTP client - Servo has very basic HTTP handling. Needs to be improved with correct handling of various responses, etc. Basically, implement the spec. https://github.com/brson/rust-http-client Libraries (not all are appropriate for std): * A general SQL interface with bindings for a few popular DBs. * An ORM framework - these are popular and useful * An actor library that encapsulates the actor pattern into something principles. Take inspiration from Scala actors. * XML From dteller at mozilla.com Wed Aug 22 00:28:19 2012 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Wed, 22 Aug 2012 09:28:19 +0200 Subject: [rust-dev] Student projects In-Reply-To: <5033E7C0.9080401@mozilla.com> References: <503381CA.80609@mozilla.com> <5033E7C0.9080401@mozilla.com> Message-ID: <50348A13.1080606@mozilla.com> On 8/21/12 9:55 PM, Brian Anderson wrote: > Here are some ideas. Servo is probably a fertile area for contributing > to Rust since there are seemingly so many things that will eventually be > needed, but so far we've not been successful at enumerating them. > > Core Rust stuff: > > * Move bindgen into the rust repo and implement a bindgen pass > (automatically generate C bindings). Involves some unsavory hacking > on the build system. Do we have documentation on bindgen to which we could link? > * Extract the metadata module from rustc and use it to implement type > safe dynamic library loading. Same here. > * Convert shape code (logging, cycle collection) to visitor code. > Probably not fun. I am not really sure I understand what this task is all about. > * Get rustc working with the LLVM MC-JIT, with the intent of > implementing a REPL. Several people have poked at this without making > much progress I like the idea. > * Improve the performance of #fmt. Could involve creating a string > builder. Ok. > > Servo-related things: > > * PNG, JPG decoders - servo is using native code currently. > * Add an LRU-SP cache - https://github.com/mozilla/servo/issues/51 > * HTTP client - Servo has very basic HTTP handling. Needs to be improved > with correct handling of various responses, etc. Basically, implement > the spec. https://github.com/brson/rust-http-client Ok. > Libraries (not all are appropriate for std): > > * A general SQL interface with bindings for a few popular DBs. > * An ORM framework - these are popular and useful > * An actor library that encapsulates the actor pattern into something > principles. Take inspiration from Scala actors. That sounds fun. I suspect that actors (and channel-to-actors, if we end up doing distributed computations) will end up implementation of traits, so I guess this will depend on traits. > * XML I like it. Perhaps with a nice set of macros for pattern-matching? Cheers, David -- David Rajchenbach-Teller, PhD Performance Team, Mozilla -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: OpenPGP digital signature URL: From rsollid at gmail.com Tue Aug 21 10:33:11 2012 From: rsollid at gmail.com (Reidar Sollid) Date: Tue, 21 Aug 2012 19:33:11 +0200 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 Message-ID: Hi, JavaZone 2012 have accepted my lightning talk on Rust, it is just 10 min so it is not much time to present Rust http://javazone.no/incogito10/events/JavaZone%202012/sessions#a8b2bb04-03f2- 4e88-9663-8387692af0e0 I am deffently doing task, but I need to build up to the tasks. Any suggestions on what to press in during those 10 min to convince Java devs that Rust is a great language? Best regards Reidar Sollid -------------- next part -------------- An HTML attachment was scrubbed... URL: From graydon at mozilla.com Thu Aug 23 14:31:50 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Thu, 23 Aug 2012 14:31:50 -0700 Subject: [rust-dev] Student projects In-Reply-To: <50348A13.1080606@mozilla.com> References: <503381CA.80609@mozilla.com> <5033E7C0.9080401@mozilla.com> <50348A13.1080606@mozilla.com> Message-ID: <5036A146.20505@mozilla.com> On 12-08-22 12:28 AM, David Rajchenbach-Teller wrote: > On 8/21/12 9:55 PM, Brian Anderson wrote: >> Here are some ideas. Servo is probably a fertile area for contributing >> to Rust since there are seemingly so many things that will eventually be >> needed, but so far we've not been successful at enumerating them. >> >> Core Rust stuff: >> >> * Move bindgen into the rust repo and implement a bindgen pass >> (automatically generate C bindings). Involves some unsavory hacking >> on the build system. > > Do we have documentation on bindgen to which we could link? As is common in free software, the source repo is the best place to look: https://github.com/crabtw/rust-bindgen It's a relatively straightforward tool (though very useful!) It links against libclang, uses that to read C header files, and emits the equivalent declarations of external symbols declared in the C header file as rust. This allows subsequent users of that rust code to link against the library described by the C header file and call its functions. The work that needs doing is integration and enhancement. I think, ideally, we'd like to have a mode wherein it can be used _inline_ in as a syntax extension, like include_c_decls!("foo.h") or such, as well as in the "pre-generate the bindings" mode it currently operates in. >> * Extract the metadata module from rustc and use it to implement type >> safe dynamic library loading. > > Same here. This is quite undocumented, and would require close collaboration with one of the full timers, likely Brian, Patrick or myself (guessing; chime in if this is also an area you know!) >> * Convert shape code (logging, cycle collection) to visitor code. >> Probably not fun. > > I am not really sure I understand what this task is all about. Currently a number of ubiquitous polymorphic actions (copying, freeing, comparing, garbage-collecting, logging) in rust are implemented through a system called "shapes". A shape is a .. sort of ad-hoc byte-coded representation of a type that is emitted in the data section of a rust binary, used to drive a miniature "interpreter" at runtime (quite fast) that performs the polymorphic actions on the types in question. We initially handled such ubiquitous actions by generating per-type "glue" code -- little helper functions emitted by the compiler once-per-type -- but found we were generating too much code. Shapes were our second attempt at solving the problem. They're more compact, but the supporting code is also comparatively slow, and more seriously, quite inflexible and hard to maintain and debug. So we're part way through a _third_ attempt here, hopefully our final attempt, wherein the compiler emits a single "visitor" function per type, that drives a callback interface. The ubiquitous polymorphic actions are then to be implemented in rust code, passing specific implementations of the callback interface to the visitor functions. We presently believe this will yield a desirable balance between speed, simplicity, flexibility and maintainability. We are only part way complete on this task though. We've built the interface, tested that it works, and are awaiting "finding sufficient time" to transition all the shape-using code over to be visitor-using. A student could possibly do some of this work. >> * Get rustc working with the LLVM MC-JIT, with the intent of >> implementing a REPL. Several people have poked at this without making >> much progress > > I like the idea. We all do! But it will not be a minor task, I suspect. Still, even standardizing and integrating the front-end-parts of a repl would be a good step; we have had a few people write them up from time to time and have so far failed to coordinate centralizing effort on a single one, so we get some overlapping effort. >> Libraries (not all are appropriate for std): >> >> * A general SQL interface with bindings for a few popular DBs. >> * An ORM framework - these are popular and useful >> * An actor library that encapsulates the actor pattern into something >> principles. Take inspiration from Scala actors. > > That sounds fun. I suspect that actors (and channel-to-actors, if we end > up doing distributed computations) will end up implementation of traits, > so I guess this will depend on traits. Traits work today, to a reasonable extent. They lack some features that are essential for factoring, but I wouldn't consider this entirely "blocked". We'll be pushing through the remaining significant pieces in short order; certainly by november. > >> * XML > I like it. Perhaps with a nice set of macros for pattern-matching? Yes. I should add to this the integration-into-libstd of a few such things: - A regexp library. There have been PCRE bindings done before but I lean a bit towards re2 in recent times. In any case, "a good one", that we support long-term. - A library for working with bitstreams, bit patterns, etc. This is very well supported in erlang and they get a lot of benefit from taking a pattern-driven approach to packed-binary formats and protocols. Another place I'd like to follow their lead. (http://www.erlang.org/doc/programming_examples/bit_syntax.html) - A classical parser-generator for general CFGs. GLR or Earley or such. This should, like the previous two, be integrated into syntax extensions or library code such that grammars can just be written inline. (And/or a parser-combinator library with good performance) - One or more "more robust" serialization libraries. Again, speaking from current preference, I've noted a couple times my interest in having a good implementation of avro. Others would like to see a thrift and/or protobuf implementation. - More standard data structures. This is some "banging out textbooks" work, but I would like to see more complete set of containers, at least alists, functional LLRBs, priority queues, cuckoo hashtables, digital tries, circular buffers, skip lists, etc. - Clients for various higher-level internet protocols. The HTTP one Brian mentioned, of course, as well as things like SMTP, FTP, IMAP, IRC, NNTP, SSH, DNS, LDAP. IOW, sure, we always have more work to do than we can possibly do ourselves. Extra hands very welcome. -Graydon From banderson at mozilla.com Thu Aug 23 15:48:07 2012 From: banderson at mozilla.com (Brian Anderson) Date: Thu, 23 Aug 2012 15:48:07 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: Message-ID: <5036B327.7080202@mozilla.com> On 08/21/2012 10:33 AM, Reidar Sollid wrote: > Hi, > > JavaZone 2012 have accepted my lightning talk on Rust, it is just 10 min > so it is not much time to present Rust > > http://javazone.no/incogito10/events/JavaZone%202012/sessions#a8b2bb04-03f2-4e88-9663-8387692af0e0 > > I am deffently doing task, but I need to build up to the tasks. > > Any suggestions on what to press in during those 10 min to convince Java > devs that Rust is a great language? Hi Reidar, This is very cool! I'm not too in-tune with the Java world right now, but here are some notes comparing Java and Rust. Two big selling points for a Java programmer are freedom from data races and control over memory layout, and these are both topics relevant to introducing Rust tasks. Java has a complex memory model describing what happens when multiple threads access shared memory. Rust has no shared memory, no volatile keyword, no synchronized methods. Synchronization in Rust is almost always based on message passing instead of locks. That's not to say that Rust's memory model isn't complex, but it's complex in entirely different ways. In Rust you have several options on for where to place objects in memory. If you try you can completely avoid the garbage collected heap. The Rust division between the GC heap and the exchange heap is what allows Rust to avoid data races. Rust and Java share some qualities: * Safety guarantees - never crash, never write bad memory * Both allow locals to be declared and assigned in separate statements while ensuring that they are definitely initialized before use. * Existential types - Rust traits can be used like Java interfaces by casting the type to the trait, though this isn't the typical usage because it involves vtables and is less efficient than using traits to place bounds on type parameters. Here are some common Java grips that Rust potentially can do better: * No data races - there's no complex model describing when variables are between threads, no volatiles. * Global GC - Java has notorious stop-the-world GC behavior (though it is very good). Rust's GC is per-task so when one task is collecting others continue running in parallel. With care you can in theory write tasks that never GC. * Lambda expressions - Rust has a very simple syntax, so Rust code uses them everywhere, whereas Java needs a lot of ceremony to do function-y things. Differences * Unsafe sublanguage - Rust gives you low level control when you need it * Control over memory layout - Local heap/echange heap/stack * Iterators - Rust uses higher-order functions instead of iterator objects * Expressiveness - Rust code is fairly compact. A determination to avoid 'public static void main' is the biggest influence of Java on Rust. Good luck with your talk! Regards, Brian From graydon at mozilla.com Thu Aug 23 16:36:55 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Thu, 23 Aug 2012 16:36:55 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: <5036B327.7080202@mozilla.com> References: <5036B327.7080202@mozilla.com> Message-ID: <5036BE97.5060905@mozilla.com> On 12-08-23 3:48 PM, Brian Anderson wrote: > Differences > > * Unsafe sublanguage - Rust gives you low level control when you need it > * Control over memory layout - Local heap/echange heap/stack > * Iterators - Rust uses higher-order functions instead of iterator objects > * Expressiveness - Rust code is fairly compact. A determination to avoid > 'public static void main' is the biggest influence of Java on Rust. *laughs* that's possibly true -- we do tend to view Java (and Ada) as verbosity high-water-marks to avoid -- but there are a few other influences I can point out: - Our liveness checker (and ex-typestate-system) are in some ways similar to the definite assignment analysis in java. - Our (creeping-into-existence) reflection layer, our existing in-crate metadata, our somewhat draconian restrictions on our own grammar, our attribute and doc-comment system and our compiler-as-a-library and extension mechanisms in the compiler are all at least partly inspired by the remarkable difference in tool maturity and power between C++ and Java. We'd like the language to be (eventually) as amenable to tooling as Java, or as near as can be without requiring a byte-code IR. - Rust has unsigned types, local type inference, disjoint unions, tuples, a variety of "nicer" type-system things of this sort. - We have tried to avoid a number of pain points we see in Java: - Ubiquitous heap allocation - Ubiquitous locking - Virtual-by-default dispatch - Finalizers rather than destructors But really, the _main_ difference is the focus on ahead-of-time, native compilation to standard executables and libraries, rather than bytecode and managed runtimes / virtual machines / JITs. This decision influences a _lot_ of the subsequent design tradeoffs. Hth, and good luck! -Graydon From sebastian.sylvan at gmail.com Thu Aug 23 17:05:30 2012 From: sebastian.sylvan at gmail.com (Sebastian Sylvan) Date: Thu, 23 Aug 2012 17:05:30 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: <5036B327.7080202@mozilla.com> References: <5036B327.7080202@mozilla.com> Message-ID: On Thu, Aug 23, 2012 at 3:48 PM, Brian Anderson wrote: > > * No data races - there's no complex model describing when variables are > between threads, no volatiles. > * Global GC - Java has notorious stop-the-world GC behavior (though it is > very good). Rust's GC is per-task so when one task is collecting others > continue running in parallel. With care you can in theory write tasks that > never GC. > * Lambda expressions - Rust has a very simple syntax, so Rust code uses > them everywhere, whereas Java needs a lot of ceremony to do function-y > things. Rust doesn't have null pointer crashes. In fact, I'm kinda ambivalent about calling a language where any reference may blow up "memory safe". IME the vast majority of runtime crashes in Java/C# are null pointer exceptions, so eliminating those are not an insigificant benefit. -- Sebastian Sylvan From banderson at mozilla.com Thu Aug 23 17:54:01 2012 From: banderson at mozilla.com (Brian Anderson) Date: Thu, 23 Aug 2012 17:54:01 -0700 Subject: [rust-dev] Student projects In-Reply-To: <5036A146.20505@mozilla.com> References: <503381CA.80609@mozilla.com> <5033E7C0.9080401@mozilla.com> <50348A13.1080606@mozilla.com> <5036A146.20505@mozilla.com> Message-ID: <5036D0A9.3080004@mozilla.com> On 08/23/2012 02:31 PM, Graydon Hoare wrote: > > IOW, sure, we always have more work to do than we can possibly do > ourselves. Extra hands very welcome. > Here are more ideas I pulled out of the issue tracker. * Implement big integers - https://github.com/mozilla/rust/issues/33 * Add compiler-inserted yield checks - task scheduling is totally unfair, and part of the problem is that tasks don't yield automatically yet unless they are using library functions that must yield for correctness. https://github.com/mozilla/rust/issues/524 * Add static crate linking - there is some bitrotted code for this already. https://github.com/mozilla/rust/issues/552 * Add a 1:1 task:thread scheduling mode, collect some performance numbers. https://github.com/mozilla/rust/issues/595 * Add config files, build-generated lists of attributes that are merged into the crate attributes. https://github.com/mozilla/rust/issues/612 * Fix debug info. Rust code can't really be debugged. Still. This is some serious compiler hacking. * Get gcov working (code coverage). Probably depends on the above. https://github.com/mozilla/rust/issues/690 * Add a task monitor. This would probably be a named service that can be queried for the task state, can provide messages on task lifecycle events. Also give tasks useful names. * Add a #[deprecated] attribute. Easy lint check. https://github.com/mozilla/rust/issues/723 * Write or finish a pygments lexer, upstream it, and get github to use it to syntax highlight Rust code. https://github.com/mozilla/rust/issues/1198 * Improve cargo. This is an open-ended problem, as we don't have a firm design in mind. * Improve rustdoc. As above, the tool exists, but isn't great. * Add command-line configuration of runtime environment. https://github.com/mozilla/rust/issues/1497 * Improve the formal rust grammar and make it testable. https://github.com/mozilla/rust/issues/2234 * Add more lint checks. The issue tracker has several open requests From niko at alum.mit.edu Thu Aug 23 18:48:47 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Thu, 23 Aug 2012 18:48:47 -0700 Subject: [rust-dev] Student projects In-Reply-To: <5036A146.20505@mozilla.com> References: <503381CA.80609@mozilla.com> <5033E7C0.9080401@mozilla.com> <50348A13.1080606@mozilla.com> <5036A146.20505@mozilla.com> Message-ID: <5036DD7F.4040401@alum.mit.edu> On 8/23/12 2:31 PM, Graydon Hoare wrote: > The work that needs doing is integration and enhancement. I think, > ideally, we'd like to have a mode wherein it can be used _inline_ in > as a syntax extension, like include_c_decls!("foo.h") or such, as well > as in the "pre-generate the bindings" mode it currently operates in. One other thing that might be nice is converting C macros to Rust macros or constants, at least where trivially possible (are Rust macros a complete superset?) Certainly for something like JSAPI this would be very helpful. Niko From olson.jeffery at gmail.com Thu Aug 23 19:04:30 2012 From: olson.jeffery at gmail.com (Jeffery Olson) Date: Thu, 23 Aug 2012 19:04:30 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: <5036B327.7080202@mozilla.com> Message-ID: As a C# developer, I definitely do *agree* with the above statement. Simultaneously, Option doesn't solve all of our problems. Putting aside whether this is a troll on Scala devs, considering the following: http://beust.com/weblog/2012/08/19/a-note-on-null-pointers/ "...but don?t listen to people who tell you that because you are no longer seeing any null pointer exceptions, your code is safer. It?s not. You still have to fix your bugs." Food for thought. But yes, I do enjoy the lack of NREs (as they're colloquially referred to in .NET land) working w/ Rust. Cheers, Jeff From lists.rust at dbp.mm.st Thu Aug 23 19:09:31 2012 From: lists.rust at dbp.mm.st (Daniel Patterson) Date: Thu, 23 Aug 2012 22:09:31 -0400 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: <5036B327.7080202@mozilla.com> Message-ID: <6BA3EBBB-352F-49E0-8AB1-55A9BA5FDCC1@dbp.mm.st> The difference is that you know where you can get a null pointer, and where you can't. If you wrap everything with Option, then you will be no better off. The hope is that often you can avoid this (i.e., write pure code that cannot go wrong, or isolate and deal with errors), and then you _will_ be better off. On Aug 23, 2012, at 10:04 PM, Jeffery Olson wrote: > As a C# developer, I definitely do *agree* with the above statement. > Simultaneously, Option doesn't solve all of our problems. > > Putting aside whether this is a troll on Scala devs, considering the following: > > http://beust.com/weblog/2012/08/19/a-note-on-null-pointers/ > > "...but don?t listen to people who tell you that because you are no > longer seeing any null pointer exceptions, your code is safer. It?s > not. You still have to fix your bugs." > > Food for thought. But yes, I do enjoy the lack of NREs (as they're > colloquially referred to in .NET land) working w/ Rust. > > Cheers, > Jeff > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From graydon at mozilla.com Thu Aug 23 19:15:40 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Thu, 23 Aug 2012 19:15:40 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: <5036B327.7080202@mozilla.com> Message-ID: <5036E3CC.5050900@mozilla.com> On 12-08-23 7:04 PM, Jeffery Olson wrote: > As a C# developer, I definitely do *agree* with the above statement. > Simultaneously, Option doesn't solve all of our problems. > > Putting aside whether this is a troll on Scala devs, considering the following: > > http://beust.com/weblog/2012/08/19/a-note-on-null-pointers/ > > "...but don?t listen to people who tell you that because you are no > longer seeing any null pointer exceptions, your code is safer. It?s > not. You still have to fix your bugs." Yes and no. I agree that it's not a panacea; you can obviously still have a malformed value. But static refinement of an X-or-Y type into independent just-X, just-Y, and X-or-Y types does help you notice (and eliminate) cases where you mean one and not the other. Any time you constrain your statically legal state-space, you tend to kill off a big chunk of bugs. (Nonexistent state-space, like not-written code, carries no bugs :) -Graydon From olson.jeffery at gmail.com Thu Aug 23 20:16:47 2012 From: olson.jeffery at gmail.com (Jeffery Olson) Date: Thu, 23 Aug 2012 20:16:47 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: <5036E3CC.5050900@mozilla.com> References: <5036B327.7080202@mozilla.com> <5036E3CC.5050900@mozilla.com> Message-ID: > Yes and no. I agree that it's not a panacea; This was, pretty much, the only point I wanted to advance. Although we still have void pointers in the form of FFI And, to be fair, another major plank of the linked post was that Option-style library APIs aren't ubiquitous even in Scala, and certainly not in the larger Java Class Library. This is not true for Rust, where Options (or Result)-style APIs exist idiomatically through the libraries (much to users chagrine, at times, anecdotally at least if feedback from net::tcp is any indicator :) From banderson at mozilla.com Fri Aug 24 00:48:15 2012 From: banderson at mozilla.com (Brian Anderson) Date: Fri, 24 Aug 2012 00:48:15 -0700 Subject: [rust-dev] Student projects In-Reply-To: <50348A13.1080606@mozilla.com> References: <503381CA.80609@mozilla.com> <5033E7C0.9080401@mozilla.com> <50348A13.1080606@mozilla.com> Message-ID: <503731BF.5060408@mozilla.com> On 08/22/2012 12:28 AM, David Rajchenbach-Teller wrote: > On 8/21/12 9:55 PM, Brian Anderson wrote: >> Here are some ideas. Servo is probably a fertile area for contributing >> to Rust since there are seemingly so many things that will eventually be >> needed, but so far we've not been successful at enumerating them. >> >> Core Rust stuff: >> >> * Move bindgen into the rust repo and implement a bindgen pass >> (automatically generate C bindings). Involves some unsavory hacking >> on the build system. > Do we have documentation on bindgen to which we could link? Oh my. I apologize for the terse descriptions. Graydon explained them well but here are links to the relevant issues for bindgen https://github.com/mozilla/rust/issues/2045 https://github.com/mozilla/rust/issues/2124 https://github.com/mozilla/rust/issues/2805 >> * Extract the metadata module from rustc and use it to implement type >> safe dynamic library loading. > Same here. Upon reflection this is a very large project without a clear design. https://github.com/mozilla/rust/issues/2213 https://github.com/mozilla/rust/issues/458 From hatahet at gmail.com Fri Aug 24 10:13:25 2012 From: hatahet at gmail.com (Ziad Hatahet) Date: Fri, 24 Aug 2012 10:13:25 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: <5036B327.7080202@mozilla.com> <5036E3CC.5050900@mozilla.com> Message-ID: On Thu, Aug 23, 2012 at 8:16 PM, Jeffery Olson wrote: > > And, to be fair, another major plank of the linked post was that > Option-style library APIs aren't ubiquitous even in Scala, and > certainly not in the larger Java Class Library. This is not true for > Rust, where Options (or Result)-style APIs exist > idiomatically through the libraries ... I am still new to using a language with an Option type (I come from an imperative language background,) but wouldn't it be preferable to try to mitigate the number of calls that return an Option type as opposed to returning an actual reference as references cannot be null/nil in Rust? Of course that probably does not apply where an error or failure might happen (such as IO). Thanks, -- Ziad -------------- next part -------------- An HTML attachment was scrubbed... URL: From nejucomo at gmail.com Fri Aug 24 13:01:48 2012 From: nejucomo at gmail.com (Nathan) Date: Fri, 24 Aug 2012 13:01:48 -0700 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: <5036B327.7080202@mozilla.com> <5036E3CC.5050900@mozilla.com> Message-ID: On Fri, Aug 24, 2012 at 10:13 AM, Ziad Hatahet wrote: > On Thu, Aug 23, 2012 at 8:16 PM, Jeffery Olson > wrote: >> >> >> And, to be fair, another major plank of the linked post was that >> Option-style library APIs aren't ubiquitous even in Scala, and >> certainly not in the larger Java Class Library. This is not true for >> Rust, where Options (or Result)-style APIs exist >> idiomatically through the libraries ... > > > I am still new to using a language with an Option type (I come from an > imperative language background,) but wouldn't it be preferable to try to > mitigate the number of calls that return an Option type as opposed to > returning an actual reference as references cannot be null/nil in Rust? Of > course that probably does not apply where an error or failure might happen > (such as IO). > I believe you will find this just "naturally" happens: If you're writing code that is intended to produce a value, but you find there are cases where it cannot, then perhaps option would make that explicit and type safe for that code and the caller. There might be other alternative approaches, but hopefully the type system forces you to deal with the case. option is a way to pass the buck to the caller, *except* it is explicit (unlike everything-may-be-null languages where it is effectively implicit). If on the other hand, you're writing code and see that in every case it has a concrete value, then there's no need for option. I think you'll find that it is natural to drop the type from option in this case to T when writing new code, because it's simply less effort for the benefit of fewer cases to produce and deal with. At first it may seem cumbersome if you are *refactoring* an API and change a T to and option, but if you think about it, in an everything-may-be-null language where you do *not* have to refactor, you've just introduced many potential bugs without realizing it. Going the other way, where you refactor an option to a T, you'll find that you just end up deleting a bunch of now unused code. And what is more rewarding than deleting code? One last point about runtime errors: I'm not familiar with how rust handles these, but I believe it would require work and also lead to poor apis if runtime errors are translated into none options. This would be akin to swallowing an exception and returning null in a language like Java/python/javascript, except in rust the caller would be forced to deal with that case. > Thanks, > > -- > Ziad > > Nathan > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From steven099 at gmail.com Fri Aug 24 13:20:42 2012 From: steven099 at gmail.com (Steven Blenkinsop) Date: Fri, 24 Aug 2012 16:20:42 -0400 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: References: <5036B327.7080202@mozilla.com> <5036E3CC.5050900@mozilla.com> Message-ID: On Friday, August 24, 2012, Nathan wrote: > On Fri, Aug 24, 2012 at 10:13 AM, Ziad Hatahet > > wrote: > > On Thu, Aug 23, 2012 at 8:16 PM, Jeffery Olson > > > > wrote: > >> > >> > >> And, to be fair, another major plank of the linked post was that > >> Option-style library APIs aren't ubiquitous even in Scala, and > >> certainly not in the larger Java Class Library. This is not true for > >> Rust, where Options (or Result)-style APIs exist > >> idiomatically through the libraries ... > > > > > > I am still new to using a language with an Option type (I come from an > > imperative language background,) but wouldn't it be preferable to try to > > mitigate the number of calls that return an Option type as opposed to > > returning an actual reference as references cannot be null/nil in Rust? > Of > > course that probably does not apply where an error or failure might > happen > > (such as IO). > > > > I believe you will find this just "naturally" happens: > > If you're writing code that is intended to produce a value, but you > find there are cases where it cannot, then perhaps option would > make that explicit and type safe for that code and the caller. There > might be other alternative approaches, but hopefully the type system > forces you to deal with the case. option is a way to pass the buck > to the caller, *except* it is explicit (unlike everything-may-be-null > languages where it is effectively implicit). > > If on the other hand, you're writing code and see that in every case > it has a concrete value, then there's no need for option. I think > you'll find that it is natural to drop the type from option in this > case to T when writing new code, because it's simply less effort for > the benefit of fewer cases to produce and deal with. > > At first it may seem cumbersome if you are *refactoring* an API and > change a T to and option, but if you think about it, in an > everything-may-be-null language where you do *not* have to refactor, > you've just introduced many potential bugs without realizing it. > Going the other way, where you refactor an option to a T, you'll > find that you just end up deleting a bunch of now unused code. And > what is more rewarding than deleting code? > > > One last point about runtime errors: I'm not familiar with how rust > handles these, but I believe it would require work and also lead to > poor apis if runtime errors are translated into none options. This > would be akin to swallowing an exception and returning null in a > language like Java/python/javascript, except in rust the caller would > be forced to deal with that case. > That's what a `result` is for. http://dl.rust-lang.org/doc/core/result.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From jruderman at gmail.com Sat Aug 25 09:57:28 2012 From: jruderman at gmail.com (Jesse Ruderman) Date: Sat, 25 Aug 2012 12:57:28 -0400 Subject: [rust-dev] A plea for removing context-free ambiguity / context-required parsing In-Reply-To: References: <502E984A.6000302@mozilla.com> Message-ID: A warning for unused pattern bindings would help: https://github.com/mozilla/rust/issues/941 From pwalton at mozilla.com Sat Aug 25 12:36:55 2012 From: pwalton at mozilla.com (Patrick Walton) Date: Sat, 25 Aug 2012 12:36:55 -0700 Subject: [rust-dev] RFC: "extern" reform Message-ID: <50392957.5010503@mozilla.com> Hi everyone, Currently, the keyword "extern" is highly overloaded. "extern" has the following meanings: 1. "extern fn" in a type means "a function that closes over nothing" (at least at one point; if this has already changed then disregard.) 2. "extern fn" in a declaration means "a function callable as a callback from C to Rust". In this case the type is actually *u8, not "extern fn". The latter means something completely different -- namely, (1) above -- a fact that causes numerous problems, including the inability to write generic callbacks. 3. "extern mod foo { ... }" means "a module of C functions in a native library called foo". 4. "extern mod foo;" means "link to the Rust crate named foo". These multiple meanings of the keyword "extern" seem highly confusing. To fix this, I propose the following changes: (a) Fix #1 above by making the type of a Rust function that closes over nothing simply "&static/fn(...) -> ...". (b) Fix #2 above by making the type of such callbacks "extern fn(...) -> ...". (c) Fix #4 by changing the syntax to link against a crate to something else. I don't really have any opinions as to what the exact syntax should be; the proposed "link" keyword seems like a fine choice, or maybe something like "use lib". Thoughts? Patrick From stevej at fruitless.org Sun Aug 26 18:33:55 2012 From: stevej at fruitless.org (Steve Jenson) Date: Sun, 26 Aug 2012 18:33:55 -0700 Subject: [rust-dev] Questions about rust's OO. Message-ID: Hi rustics, I spent some time this weekend going over the rust tutorial and documentation for 0.3.1. I thought a fun exercise would be writing an xUnit testing framework[1] in a "classic" OO style. I ran into a few problems: 1) xUnit historically relies on inheritance but it's not clear to me how to model an is-a relationship in Rust. For instance, define an abstract base class (TestSuite) and an implementation that tests a set of functions (say, a calculator). 2) How to colocate state and behavior in impls. Embedding lets in my impls results in errors. 3) Reflection. I have no documented way to iterate over the functions in an impl and call them. (I'm sure this is on the way and I'm just early to the party) I also think I'm approaching this from the wrong direction and that Rust's OO with typeclasses are different from how I'm using to building software in another language with typeclasses (Scala). I'm still looking for the zen of Rust OO. I ran into some old blog posts that discuss a class keyword but I wasn't able to make those examples run in 0.3.1. Do we only have impls now? I realize that Rust is young and moving quickly but I'm struggling to build something that's more than a few functions and an enum. Thanks a bunch, Steve [1] http://en.wikipedia.org/wiki/XUnit From catamorphism at gmail.com Sun Aug 26 18:45:49 2012 From: catamorphism at gmail.com (Tim Chevalier) Date: Sun, 26 Aug 2012 18:45:49 -0700 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: References: Message-ID: On Sun, Aug 26, 2012 at 6:33 PM, Steve Jenson wrote: > Hi rustics, > > I spent some time this weekend going over the rust tutorial and > documentation for 0.3.1. I thought a fun exercise would be writing an > xUnit testing framework[1] in a "classic" OO style. I ran into a few > problems: > > 1) xUnit historically relies on inheritance but it's not clear to me > how to model an is-a relationship in Rust. For instance, define an > abstract base class (TestSuite) and an implementation that tests a set > of functions (say, a calculator). > Hi, Steve -- The way to do this in Rust would be to define a trait TestSuite, and impls that implement that trait for various types. Patrick's tutorial should be helpful: http://pcwalton.github.com/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/ > 2) How to colocate state and behavior in impls. Embedding lets in my > impls results in errors. impls don't talk about state, and we don't have plans to change that as far as I know. As shown in Patrick's tutorial, you define all your fields in struct definitions, and then provide impls that implement various traits for a particular struct. This doesn't preclude anything: you can always define methods on a struct that get/set its fields. > > 3) Reflection. I have no documented way to iterate over the functions > in an impl and call them. (I'm sure this is on the way and I'm just > early to the party) > I don't know of any plans to do this. I'm not sure why you would want to; if you can give an example, it might help. > I also think I'm approaching this from the wrong direction and that > Rust's OO with typeclasses are different from how I'm using to > building software in another language with typeclasses (Scala). I'm > still looking for the zen of Rust OO. > > I ran into some old blog posts that discuss a class keyword but I > wasn't able to make those examples run in 0.3.1. Do we only have impls > now? The class keyword is deprecated; struct replaces class. Feel free to ask again if you have more questions (or visit #rust on IRC). Cheers, Tim -- Tim Chevalier * http://catamorphism.org/ * Often in error, never in doubt "Debate is useless when one participant denies the full dignity of the other." -- Eric Berndt From stevej at fruitless.org Sun Aug 26 19:25:46 2012 From: stevej at fruitless.org (Steve Jenson) Date: Sun, 26 Aug 2012 19:25:46 -0700 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: References: Message-ID: On Sun, Aug 26, 2012 at 6:45 PM, Tim Chevalier wrote: > On Sun, Aug 26, 2012 at 6:33 PM, Steve Jenson wrote: >> Hi rustics, >> >> I spent some time this weekend going over the rust tutorial and >> documentation for 0.3.1. I thought a fun exercise would be writing an >> xUnit testing framework[1] in a "classic" OO style. I ran into a few >> problems: >> >> 1) xUnit historically relies on inheritance but it's not clear to me >> how to model an is-a relationship in Rust. For instance, define an >> abstract base class (TestSuite) and an implementation that tests a set >> of functions (say, a calculator). >> > > Hi, Steve -- > > The way to do this in Rust would be to define a trait TestSuite, and > impls that implement that trait for various types. Patrick's tutorial > should be helpful: > > http://pcwalton.github.com/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/ Based on that, I came up with a super naive attempt. I realize this is basically trying to write Java in rust so I apologize in advance. trait TestSuite { fn setup(); fn teardown(); } struct Calculator { fn add(m: int, n: int) -> int { return m + n; } } impl CalculatorTest : TestSuite { // error: use of undeclared type name `CalculatorTest` // without this, I have nothing to call //let calculator = Calculator(); fn setup() {} fn teardown() {} fn test_addition() -> bool { return true; } } Based on my experience in Haskell, there's a number of ways I could tackle this problem but I think it's safe to say that most people who think of themselves as 'systems programmers' would attempt the above first and wonder why rust's OO is 'weird'? I'm also curious what a rust-oriented solution to this problem would look like. >> 2) How to colocate state and behavior in impls. Embedding lets in my >> impls results in errors. > > impls don't talk about state, and we don't have plans to change that > as far as I know. As shown in Patrick's tutorial, you define all your > fields in struct definitions, and then provide impls that implement > various traits for a particular struct. This doesn't preclude > anything: you can always define methods on a struct that get/set its > fields. > >> >> 3) Reflection. I have no documented way to iterate over the functions >> in an impl and call them. (I'm sure this is on the way and I'm just >> early to the party) >> > > I don't know of any plans to do this. I'm not sure why you would want > to; if you can give an example, it might help. In a traditional xUnit framework, your test suite subclasses have methods that are prefixed with 'test' and you use reflection to iterate over the methods and call each method whose name starts with 'test', calling setup() and teardown() around each invocation. In a BDD framework, you build tests as anonymous functions and you can register them and call them without resorting to reflection. In rust, this would look something like: describe('add two numbers', fun () -> bool { assertEqual(calc.add(1, 1), 2) }); >> I also think I'm approaching this from the wrong direction and that >> Rust's OO with typeclasses are different from how I'm using to >> building software in another language with typeclasses (Scala). I'm >> still looking for the zen of Rust OO. >> >> I ran into some old blog posts that discuss a class keyword but I >> wasn't able to make those examples run in 0.3.1. Do we only have impls >> now? > > The class keyword is deprecated; struct replaces class. > > Feel free to ask again if you have more questions (or visit #rust on IRC). Thanks again! I hope this is helpful and doesn't seem like I'm trolling. steve From garethdanielsmith at gmail.com Mon Aug 27 02:39:09 2012 From: garethdanielsmith at gmail.com (Gareth Smith) Date: Mon, 27 Aug 2012 10:39:09 +0100 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: References: Message-ID: <503B403D.10801@gmail.com> On 27/08/12 03:25, Steve Jenson wrote: > Based on that, I came up with a super naive attempt. I realize this is > basically trying to write Java in rust so I apologize in advance. > > trait TestSuite { > fn setup(); > fn teardown(); > } > > struct Calculator { > fn add(m: int, n: int) -> int { > return m + n; > } > } > > impl CalculatorTest : TestSuite { // error: use of undeclared type name `CalculatorTest` > // without this, I have nothing to call > //let calculator = Calculator(); > > fn setup() {} > fn teardown() {} > > fn test_addition() -> bool { > return true; > } > } The impl syntax goes something like: `impl NameOfExistingType : NameOfExistingTraitThatIsBeingImplemented { ... }`. I suppose you might declare `impl Calculator : TestSuite { ... }` instead of `impl CalculatorTest : TestSuite { ... }`. I am no expert but I can't think of a natural way to replicate an inheritance based JUnit like system in rust. I guess I would try building something based on first class functions instead. An alternative though (in-case you don't already know) is the test system built in to the compiler: http://dl.rust-lang.org/doc/tutorial.html#testing. Gareth From rsollid at gmail.com Mon Aug 27 06:36:10 2012 From: rsollid at gmail.com (Reidar Sollid) Date: Mon, 27 Aug 2012 15:36:10 +0200 Subject: [rust-dev] Rust lightning talk at JavaZone 2012 In-Reply-To: <5036B327.7080202@mozilla.com> Message-ID: Hi Brian, Sorry for top-posting. Thanks a lot for great input ! Best regards Reidar On 8/24/12 12:48 AM, "Brian Anderson" wrote: >On 08/21/2012 10:33 AM, Reidar Sollid wrote: >> Hi, >> >> JavaZone 2012 have accepted my lightning talk on Rust, it is just 10 min >> so it is not much time to present Rust >> >> >>http://javazone.no/incogito10/events/JavaZone%202012/sessions#a8b2bb04-03 >>f2-4e88-9663-8387692af0e0 >> >> I am deffently doing task, but I need to build up to the tasks. >> >> Any suggestions on what to press in during those 10 min to convince Java >> devs that Rust is a great language? > >Hi Reidar, > >This is very cool! > >I'm not too in-tune with the Java world right now, but here are some >notes comparing Java and Rust. > >Two big selling points for a Java programmer are freedom from data races >and control over memory layout, and these are both topics relevant to >introducing Rust tasks. > >Java has a complex memory model describing what happens when multiple >threads access shared memory. Rust has no shared memory, no volatile >keyword, no synchronized methods. Synchronization in Rust is almost >always based on message passing instead of locks. > >That's not to say that Rust's memory model isn't complex, but it's >complex in entirely different ways. In Rust you have several options on >for where to place objects in memory. If you try you can completely >avoid the garbage collected heap. The Rust division between the GC heap >and the exchange heap is what allows Rust to avoid data races. > >Rust and Java share some qualities: > >* Safety guarantees - never crash, never write bad memory >* Both allow locals to be declared and assigned in separate statements >while ensuring that they are definitely initialized before use. >* Existential types - Rust traits can be used like Java interfaces by >casting the type to the trait, though this isn't the typical usage >because it involves vtables and is less efficient than using traits to >place bounds on type parameters. > >Here are some common Java grips that Rust potentially can do better: > >* No data races - there's no complex model describing when variables are >between threads, no volatiles. >* Global GC - Java has notorious stop-the-world GC behavior (though it >is very good). Rust's GC is per-task so when one task is collecting >others continue running in parallel. With care you can in theory write >tasks that never GC. >* Lambda expressions - Rust has a very simple syntax, so Rust code uses >them everywhere, whereas Java needs a lot of ceremony to do function-y >things. > >Differences > >* Unsafe sublanguage - Rust gives you low level control when you need it >* Control over memory layout - Local heap/echange heap/stack >* Iterators - Rust uses higher-order functions instead of iterator objects >* Expressiveness - Rust code is fairly compact. A determination to avoid >'public static void main' is the biggest influence of Java on Rust. > >Good luck with your talk! > >Regards, >Brian > >_______________________________________________ >Rust-dev mailing list >Rust-dev at mozilla.org >https://mail.mozilla.org/listinfo/rust-dev From niko at alum.mit.edu Mon Aug 27 09:39:25 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Mon, 27 Aug 2012 09:39:25 -0700 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: References: Message-ID: <503BA2BD.8070306@alum.mit.edu> Aside from the reflective aspects of JUnit, I think that the closest analogue in Rust to the use of inheritance to provide overridable methods like setup() and teardown() would be default methods in traits. Something like: trait TestSuite { fn setup() {} fn teardown() {} } struct Calculator {...} struct CalculatorTest {...} impl CalculatorTest: TestSuite { fn setup() { ... } } However, default methods are not yet implemented. Niko On 8/26/12 7:25 PM, Steve Jenson wrote: > On Sun, Aug 26, 2012 at 6:45 PM, Tim Chevalier wrote: >> On Sun, Aug 26, 2012 at 6:33 PM, Steve Jenson wrote: >>> Hi rustics, >>> >>> I spent some time this weekend going over the rust tutorial and >>> documentation for 0.3.1. I thought a fun exercise would be writing an >>> xUnit testing framework[1] in a "classic" OO style. I ran into a few >>> problems: >>> >>> 1) xUnit historically relies on inheritance but it's not clear to me >>> how to model an is-a relationship in Rust. For instance, define an >>> abstract base class (TestSuite) and an implementation that tests a set >>> of functions (say, a calculator). >>> >> Hi, Steve -- >> >> The way to do this in Rust would be to define a trait TestSuite, and >> impls that implement that trait for various types. Patrick's tutorial >> should be helpful: >> >> http://pcwalton.github.com/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/ > Based on that, I came up with a super naive attempt. I realize this is > basically trying to write Java in rust so I apologize in advance. > > trait TestSuite { > fn setup(); > fn teardown(); > } > > struct Calculator { > fn add(m: int, n: int) -> int { > return m + n; > } > } > > impl CalculatorTest : TestSuite { // error: use of undeclared type > name `CalculatorTest` > // without this, I have nothing to call > //let calculator = Calculator(); > > fn setup() {} > fn teardown() {} > > fn test_addition() -> bool { > return true; > } > } > > Based on my experience in Haskell, there's a number of ways I could > tackle this problem but I think it's safe to say that most people who > think of themselves as 'systems programmers' would attempt the above > first and wonder why rust's OO is 'weird'? > > I'm also curious what a rust-oriented solution to this problem would look like. > >>> 2) How to colocate state and behavior in impls. Embedding lets in my >>> impls results in errors. >> impls don't talk about state, and we don't have plans to change that >> as far as I know. As shown in Patrick's tutorial, you define all your >> fields in struct definitions, and then provide impls that implement >> various traits for a particular struct. This doesn't preclude >> anything: you can always define methods on a struct that get/set its >> fields. >> >>> 3) Reflection. I have no documented way to iterate over the functions >>> in an impl and call them. (I'm sure this is on the way and I'm just >>> early to the party) >>> >> I don't know of any plans to do this. I'm not sure why you would want >> to; if you can give an example, it might help. > In a traditional xUnit framework, your test suite subclasses have > methods that are prefixed with 'test' and you use reflection to > iterate over the methods and call each method whose name starts with > 'test', calling setup() and teardown() around each invocation. > > In a BDD framework, you build tests as anonymous functions and you can > register them and call them without resorting to reflection. In rust, > this would look something like: > > describe('add two numbers', fun () -> bool { assertEqual(calc.add(1, 1), 2) }); > >>> I also think I'm approaching this from the wrong direction and that >>> Rust's OO with typeclasses are different from how I'm using to >>> building software in another language with typeclasses (Scala). I'm >>> still looking for the zen of Rust OO. >>> >>> I ran into some old blog posts that discuss a class keyword but I >>> wasn't able to make those examples run in 0.3.1. Do we only have impls >>> now? >> The class keyword is deprecated; struct replaces class. >> >> Feel free to ask again if you have more questions (or visit #rust on IRC). > Thanks again! I hope this is helpful and doesn't seem like I'm trolling. > > steve > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev From banderson at mozilla.com Mon Aug 27 13:25:02 2012 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 27 Aug 2012 13:25:02 -0700 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: References: Message-ID: <503BD79E.5080508@mozilla.com> On 08/26/2012 06:33 PM, Steve Jenson wrote: > Hi rustics, > > I spent some time this weekend going over the rust tutorial and > documentation for 0.3.1. I thought a fun exercise would be writing an > xUnit testing framework[1] in a "classic" OO style. I ran into a few > problems: I'm glad you've been considering this. I have always viewed it as a goal to get an xUnit-style framework working in Rust, hopefully integrating in some way with the basic test runner built into std. Unfortunately, a lot of features necessary to do what JUnit does don't exist yet. > > 1) xUnit historically relies on inheritance but it's not clear to me > how to model an is-a relationship in Rust. For instance, define an > abstract base class (TestSuite) and an implementation that tests a set > of functions (say, a calculator). TestSuite will probably be a trait, and implementing the trait is how the test runner identifies test suites. But TestSuite itself is pretty limited in what it can implement. > > 2) How to colocate state and behavior in impls. Embedding lets in my > impls results in errors. You get a single type to represent the state of the test suite. impls don't get their own state, just the state contained in their self types. struct MyTestSuite { mut state: ... } impl MyTestSuite: TestSuite { } > > 3) Reflection. I have no documented way to iterate over the functions > in an impl and call them. (I'm sure this is on the way and I'm just > early to the party) This is the biggest roadblock to making a bigger, more dynamic testing framework. There is no reflection or dynamic function loading yet. Here are two related issues: https://github.com/mozilla/rust/issues/458 https://github.com/mozilla/rust/issues/2213 Just for the existing minimal test framework I want to be able to use reflection to grab all the #[test] functions from library crates. > > I also think I'm approaching this from the wrong direction and that > Rust's OO with typeclasses are different from how I'm using to > building software in another language with typeclasses (Scala). I'm > still looking for the zen of Rust OO. Yes, aspects of xUnit's design doesn't fit all that well with Rust, but hopefully we can borrow the parts the work and the parts that don't we can do differently. > > I ran into some old blog posts that discuss a class keyword but I > wasn't able to make those examples run in 0.3.1. Do we only have impls > now? Yes. There is no longer a self-contained class type. Structs + impls + constructor functions are the way to define objects now. > > I realize that Rust is young and moving quickly but I'm struggling to > build something that's more than a few functions and an enum. I don't blame you. There's a big mismatch here that I've struggled with as well. If we were going to outline something that looked like an xUnit test suite it would look something like this /// Marker that indicates a test suite trait TestSuite { // Something likely goes here } struct MyTestSuite { // test state goes here } impl MyTestSuite: TestSuite { fn startup() { // optional function that runs before each test } fn teardown() { // optional function that runs after each test } // Any number of test functions fn test1() { } fn test2() { } } It looks really simple, but then when you start thinking about how the test runner actually runs this type of test it gets ugly. This is what a typical xUnit runner does: 1) Find all the implementations of TestSuite 2) For each TestSuite: a) Instantiate the suite with a default constructor b) Find all the test methods dynamically c) For each test method, run startup(), the test, then teardown() Rust basically can't do any of these things yet. Let's first consider the reflection aspect. The test runner needs reflection to find the suite, the tests, possibly the startup and teardown methods. Since reflection doesn't much exist yet, we can speculate on several ways to do this. One may might be more declarative, using attributes, like NUnit (and I think later JUnit). The following would be enough to locate tests: // Don't actually need a trait just to locate a test object. An // attribute will also work. #[test_suite] struct MyTestSuite { // state } impl MyTestSuite { #[startup] // This can probably be optional, since we could just // reflect on the method name fn startup() { } fn shutdown() { } fn test() { // methods that start with 'test' are tests } #[test] fn descriptive_test_case() { // methods with the test attribute are tests } } Again, most of the machinery to make this possible does not exist. The next set of problems is around the statefulness of an xUnit test suite. xUnit wants to instantiate a mutable test suite object, then reuse it for each test, with the startup and shutdown methods typically resetting the mutable state of the test suite to initial test conditions. Without default values and null pointers Rust can't just instantiate an empty test case for you, so we'll need to tell the test runner where the constructor is. So maybe our test suite looks like the following: // I have no idea how much of this syntax is available or even under // consideration trait TestSuite { static fn new() -> T; // No default implementation fn startup(&mut self) { self <- new() // By default we completely reset our state } fn shutdown(&mut self) { } } struct MyTestSuite { mut state1: bool } impl MyTestSuite: TestSuite { static fn new() -> MyTestSuite { MyTestSuite { state1: false } } fn test() { ... } } Given a lot of assumptions about what might ultimately be available in the language, this looks like the beginnings of a workable design. Unfortunately, given the stateful nature of a test suite, you aren't going to be able to run the tests in parallel (just entire suites). Also unfortunately, it's difficult to even begin approaching this in the existing language. In the end I think the ideal test framework for Rust will look somewhat different than xUnit, be designed by default to isolate and run tests in parallel, and will treat stateful test suits with interdependent tests as a special case. Ok, maybe some of that was useful. Regards, Brian From banderson at mozilla.com Mon Aug 27 13:53:53 2012 From: banderson at mozilla.com (Brian Anderson) Date: Mon, 27 Aug 2012 13:53:53 -0700 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: References: Message-ID: <503BDE61.3070409@mozilla.com> On 08/26/2012 07:25 PM, Steve Jenson wrote: > On Sun, Aug 26, 2012 at 6:45 PM, Tim Chevalier wrote: >> On Sun, Aug 26, 2012 at 6:33 PM, Steve Jenson wrote: >>> Hi rustics, >>> >>> I spent some time this weekend going over the rust tutorial and >>> documentation for 0.3.1. I thought a fun exercise would be writing an >>> xUnit testing framework[1] in a "classic" OO style. I ran into a few >>> problems: >>> >>> 1) xUnit historically relies on inheritance but it's not clear to me >>> how to model an is-a relationship in Rust. For instance, define an >>> abstract base class (TestSuite) and an implementation that tests a set >>> of functions (say, a calculator). >>> >> >> Hi, Steve -- >> >> The way to do this in Rust would be to define a trait TestSuite, and >> impls that implement that trait for various types. Patrick's tutorial >> should be helpful: >> >> http://pcwalton.github.com/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/ > > Based on that, I came up with a super naive attempt. I realize this is > basically trying to write Java in rust so I apologize in advance. > > trait TestSuite { > fn setup(); > fn teardown(); > } > > struct Calculator { > fn add(m: int, n: int) -> int { > return m + n; > } > } > > impl CalculatorTest : TestSuite { // error: use of undeclared type > name `CalculatorTest` > // without this, I have nothing to call > //let calculator = Calculator(); > > fn setup() {} > fn teardown() {} > > fn test_addition() -> bool { > return true; > } > } > This is closer to working code in current Rust: // The type we want to test struct Calculator { need_at_least_one_field: (); // per a compiler limitation } // Methods on our type impl Calculator { fn add(m: int, n: int) -> int { ... } } // The type of a test suite trait TestSuite { fn startup(); fn teardown(); } // Our test suite struct CalculatorTest { mut calculator: Option; } impl CalculatorTest: TestSuite { fn startup() { self.calculator = Some(Calculator { need_at_least_one_field: (); }); } fn teardown() { /* nop */ } fn test() { assert self.calculator.is_some(); } } // The test suite constructor fn CalculatorTest() -> CalculatorTest { CalculatorTest { calculator: None } } > Based on my experience in Haskell, there's a number of ways I could > tackle this problem but I think it's safe to say that most people who > think of themselves as 'systems programmers' would attempt the above > first and wonder why rust's OO is 'weird'? > > I'm also curious what a rust-oriented solution to this problem would look like. > >>> 2) How to colocate state and behavior in impls. Embedding lets in my >>> impls results in errors. >> >> impls don't talk about state, and we don't have plans to change that >> as far as I know. As shown in Patrick's tutorial, you define all your >> fields in struct definitions, and then provide impls that implement >> various traits for a particular struct. This doesn't preclude >> anything: you can always define methods on a struct that get/set its >> fields. >> >>> >>> 3) Reflection. I have no documented way to iterate over the functions >>> in an impl and call them. (I'm sure this is on the way and I'm just >>> early to the party) >>> >> >> I don't know of any plans to do this. I'm not sure why you would want >> to; if you can give an example, it might help. > > In a traditional xUnit framework, your test suite subclasses have > methods that are prefixed with 'test' and you use reflection to > iterate over the methods and call each method whose name starts with > 'test', calling setup() and teardown() around each invocation. > > In a BDD framework, you build tests as anonymous functions and you can > register them and call them without resorting to reflection. In rust, > this would look something like: > > describe('add two numbers', fun () -> bool { assertEqual(calc.add(1, 1), 2) }); This would read well in Rust: do describe("add two numbers") { assert calc.add(1, 1) == 2; } > >>> I also think I'm approaching this from the wrong direction and that >>> Rust's OO with typeclasses are different from how I'm using to >>> building software in another language with typeclasses (Scala). I'm >>> still looking for the zen of Rust OO. >>> >>> I ran into some old blog posts that discuss a class keyword but I >>> wasn't able to make those examples run in 0.3.1. Do we only have impls >>> now? >> >> The class keyword is deprecated; struct replaces class. >> >> Feel free to ask again if you have more questions (or visit #rust on IRC). > > Thanks again! I hope this is helpful and doesn't seem like I'm trolling. > > steve > _______________________________________________ > Rust-dev mailing list > Rust-dev at mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > From niko at alum.mit.edu Mon Aug 27 19:48:15 2012 From: niko at alum.mit.edu (Niko Matsakis) Date: Mon, 27 Aug 2012 19:48:15 -0700 Subject: [rust-dev] RFC: "extern" reform In-Reply-To: <50392957.5010503@mozilla.com> References: <50392957.5010503@mozilla.com> Message-ID: <503C316F.1060501@alum.mit.edu> On 8/25/12 12:36 PM, Patrick Walton wrote: > (a) Fix #1 above by making the type of a Rust function that closes > over nothing simply "&static/fn(...) -> ...". For various reasons, this does not work [1]. My plan was just to remove the "bare function" type entirely and instead say that a bare fn item can be instantiated with any sigil. I should probably write that code already and remove the bare function type for good. I've been waiting a bit because (a) the existing &fn() type still needs some work and (b) I'm hoping to let the design sit in my brain a bit more, particularly as regards `once fn`. Niko [1] In short: Bare fns really ought to be assignable to @fn, ~fn, and not just &fn. From graydon at mozilla.com Tue Aug 28 08:36:13 2012 From: graydon at mozilla.com (Graydon Hoare) Date: Tue, 28 Aug 2012 08:36:13 -0700 Subject: [rust-dev] RFC: "extern" reform In-Reply-To: <50392957.5010503@mozilla.com> References: <50392957.5010503@mozilla.com> Message-ID: <503CE56D.4000709@mozilla.com> On 25/08/2012 12:36 PM, Patrick Walton wrote: > Hi everyone, > > Currently, the keyword "extern" is highly overloaded. "extern" has the > following meanings: > > 1. "extern fn" in a type means "a function that closes over nothing" (at > least at one point; if this has already changed then disregard.) I'd get rid of this, yes. Confusing. Niko suggests this can go away, yes? > 2. "extern fn" in a declaration means "a function callable as a callback > from C to Rust". In this case the type is actually *u8, not "extern fn". > The latter means something completely different -- namely, (1) above -- > a fact that causes numerous problems, including the inability to write > generic callbacks. > > 3. "extern mod foo { ... }" means "a module of C functions in a native > library called foo". > > 4. "extern mod foo;" means "link to the Rust crate named foo". I agree with your proposed (a) and (b) changes. Or at least (b). I don't understand (a) enough to comment, Niko suggests maybe the problem can evaporate, which is fine by me. 'extern' should probably be a full function type qualifier though (or indeed, 'extern ["linkage"]' as in C), if it's not already. Concerning the #3 and #4 points above, and generally their interaction with #2: these all mean something similar to what they mean in C++. Some combination of: - "this thing participates in linkage in a not-purely-local way" - "possibly let me declare this thing without defining it" I'd like to go a bit further down the road we've sketched out for these 3 first (in particular: allowing non-defining 'extern' item declarations such as function signatures and const declarations at random locations, etc.) I think parsimony with keywords is warranted here as 2/3 of the uses are infrequent in "most" rust programs, just libraries that interface to C code; that's a majority _today_ but I assume/hope it won't be forever. Moreover, the other 1/3 is still infrequent on a source-file-by-source-file basis, only written once-per-linkage (i.e. all in one file, in a large multi-file project). If case #4 continues to be a thorn (eg. in small one-file programs) I'd be ... disappointed, but ok switching it back to "link". But that's not entirely clear to me yet. (It may also be worth considering the extent to which 'extern "rust" foo' is equivalent to formalizing the lazily-imported-item concept that we were discussing yesterday at the language level, and whether that carries any additional benefits relative to hiding it as an implementation technique...) -Graydon From banderson at mozilla.com Wed Aug 29 12:04:28 2012 From: banderson at mozilla.com (Brian Anderson) Date: Wed, 29 Aug 2012 12:04:28 -0700 Subject: [rust-dev] Questions about rust's OO. In-Reply-To: <20120829183539.GA1773@mercurialalchemist> References: <503BD79E.5080508@mozilla.com> <20120829183539.GA1773@mercurialalchemist> Message-ID: <503E67BC.3040608@mozilla.com> On 08/29/2012 11:35 AM, Emmanuel Surleau wrote: > > [snip] > >> Given a lot of assumptions about what might ultimately be available >> in the language, this looks like the beginnings of a workable >> design. Unfortunately, given the stateful nature of a test suite, >> you aren't going to be able to run the tests in parallel (just >> entire suites). > > Assuming the necessary machinery is in place, what's keeping you from creating > one instance of the suite per test, and putting each of them in their own task? > > In which case, having a constructor and a destructor instead of setup/teardown > would make more sense. I think that sort of model does make more sense for Rust, but I see the setup/teardown thing as the distinctive part of the xUnit design. It may be so awkward with Rust that we shouldn't try to copy it. If you did that then a complete test suit might look like: trait TestSuite: drop { static fn new() -> self; fn drop() { ... } } struct MyTestSuite { ... } impl MyTestSuite: TestSuite { static fn new() -> self { ... } fn drop() { } fn test1() { } fn test2() { } } From dteller at mozilla.com Thu Aug 30 11:17:28 2012 From: dteller at mozilla.com (David Rajchenbach-Teller) Date: Thu, 30 Aug 2012 20:17:28 +0200 Subject: [rust-dev] Student projects In-Reply-To: <503731BF.5060408@mozilla.com> References: <503381CA.80609@mozilla.com> <5033E7C0.9080401@mozilla.com> <50348A13.1080606@mozilla.com> <503731BF.5060408@mozilla.com> Message-ID: <503FAE38.8030808@mozilla.com> Actually, it dawns to me that I could outsource this. I have put together a bug tracker for student projects that do not fit in BMO: https://github.com/Yoric/Mozilla-Student-Projects/issues?sort=created&state=open Could someone please add either the Rust-related projects or a blanket Rust project and a link to the list of issues that can be turned into student projects on the Rust bug tracker? We have one professor eager to put some of his students on Rust, so I hope that we can get something nice together. Thanks, David -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 487 bytes Desc: OpenPGP digital signature URL: