Re: [rust-dev] std::num::pow() is inadequate / language concepts
Hello Gregor, Firstly, blanket statements like "This makes generic programming impossible" and "it does not allow proper software design" are unneccesary hyperbole, and do not help the discussion in any way. Traits provide a more well-defined, easier to reason about alternative to overloading. They do require the author of an algorithm to decide ahead of time whether this algorithm needs to be specializeable, which I guess C++-style overloading does not. Whether that is a good or a bad thing is debatable, but it is not true that Rust lacks a feature for specialization. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] UTF-8 strings versus "encoded ropes"
On Thu, May 1, 2014 at 10:42 PM, Tony Arcieri wrote: > You're wrong. Though I agree with what you are arguing, starting emails in such a blunt and dismissive way does not further a pleasant mailing list climate, and I'd like to ask you to try and be more emphatic in the future. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] NewType change in 0.9
> What does wrapping the 'name' of the variable with it's type on the LHS of > the : as well as having it on the RHS? It's a destructuring pattern, extracting the content of the Row/Column values and binding a variable to it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Appeal for CORRECT, capable, future-proof math, pre-1.0
I am not aware of an efficient way to provide automatic-overflow-to-bignum semantics in a non-garbage-collected language, without also imposing the burden of references/move semantics/etc on users of small integers. I.e. integers, if they may hold references to allocated memory can no longer sanely be considered a simple value type, which doesn't seem like it'd be a good idea for Rust. If there is a good solution to this, I'd love to find out about it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] tutorial (bis)
As the author of the original tutorial I'm interested in what people hate so much about it. It appears to have slightly bit-rotted, in that the language moved on and people haphazardly updated stuff here and there, but the bulk of it still looks coherent. Can I get some concrete pointers? On Fri, Nov 15, 2013 at 3:39 PM, Daniel Micay wrote: > On Fri, Nov 15, 2013 at 9:33 AM, Gaetan wrote: >> after reading this doc, I would love to have: >> - have a link at the bottom page to the github project >> - submit one or several pullrequest >> - doc is magically updated. >> >> I'm investigating on this matter to ease documentation. That's is quite >> interesting, because in my everyday job (I'm a python developer for a >> buildbot derived project) I'm in a "write tools to ease code documentation >> and user manual maintainance" mood :) > > It gets updated by the doc builder when a pull request is merged. A > pull request will run through the auto builders before being merged, > including extracting and testing the samples in the tutorial. > > http://buildbot.rust-lang.org/ > http://buildbot.rust-lang.org/bors/bors.html > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The future of M:N threading
> Unfortunately, instead of actually fixing the underlying problem […] the > ECMAScript committee seems to have gone with […] which is lighter syntax but > still absurd. Flaming other languages / committees is very much not the point of this mailing list. Try to stay on topic and dispassionate. On Thu, Nov 14, 2013 at 6:23 AM, Bardur Arantsson wrote: > On 2013-11-13 21:41, Igor Bukanov wrote: >> On 13 November 2013 20:41, Bardur Arantsson wrote: >> >>> In practice it's much more difficult to be *explicitly* >>> async and it should just be delegated to the language/runtime. There are >>> some things humans just aren't good at. >> >> I suspect Rust makes asynchronous programming significantly more >> bearable. Programming in JS in that style is often painful due to the >> noise of all those function() { } spread through the code and bugs >> connected with accessing stuff that should only be ready later. Rust >> nicely addresses that with shorter syntax for closures/macros and move >> semantics. >> >> So an experiment of writing in asynchronous style in Rust and >> comparing that with C++/JS/other languages would be very useful to >> judge. >> > > It's *not* a matter of just making the syntax "lighter". Asynchronous > callbacks lead to "the pyramid of doom" (as Dave Herman puts it) of > nested callback functions. > > Unfortunately, instead of actually fixing the underlying problem (which > is the need for an explicit callback model in the first place), the > ECMAScript committee seems to have gone with > > function foo*(...) { > yield ; > } > > which is lighter syntax but still absurd. (To bear fair they also have > extreme constraints of backward compatibility.) > > Python has also (to my great disappointment) gone this route, but there > you can't even tell "from the outside" if a function is async-safe -- > it's not part of its interface syntactically, but it's of huge > importance in practice. > > My overall point is: Why should the *programmer* be segregating > functions into asynchronous and synchronous? We have computers and > compilers which are more than capable than doing this for us at this point! > > Regards, > > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Unified function/method call syntax and further simplification
I want to add that we did initially have a scheme where you have to import every impl you used (not every method), and that this was abandoned because it was burdensome and, in typical situations, completely redundant. Another problem with this proposal seems that it does away with the possibility of explicitly grouping a bunch of methods that make up the implementation of an interface. Implementing interfaces go-style, by just happening to have implemented all the methods that make up the interface, seems inappropriate for a language where interfaces aren't structural. So I very much agree with Patrick. Some aspects of this proposal are attractive, but it breaks some essential properties of the way methods currently work (and probably can't be adjusted to work around that without losing most of it attraction). Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Syntax for "raw" string literals
>> If I need to embed both ''' and """ in a string, I'm out of luck. > > The chance of that is as remote as can be. I've never seen or heard of > it happen. And mind, the issue must happen *in a rawstring* which is > even more unlikely. You should note that, as soon as you include something in the language itself, that creates meaningful strings (programs in the language) that include the token, which are not likely, at some point, to need to be written as a multiline string in the language itself. (As a related example, as someone writing JavaScript-analyzing code in JavaScript, I've had several bugs caused by the fact that the nonsense, no-one-is-ever-going-to-use-this word __proto__ has a very hard to suppress special meaning, and you *are* going to use it when analyzing the elements in another JavaScript program.) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Rust compiler bootstrapped
The Rust team is aware of this possibility, and is guarding against it by keeping a log of checksums and source git revisions for the various versions of the compiler, so that compilers downloaded from the net can be checked, and we could, if something dodgy is found, back-track to a known trusted version of the compiler (or even all the way back to the OCaml bootstrap compiler, though that'd be a lot of work). It is theoretically possible that someone manages to sneak in a commit that adds an exploit to the compiler, but since patches are reviewed, that is not terribly likely to succeed. Also, Rust is a small target still, and it would be a marvelous feat of engineering to install a functioning exploit in a compiler that is being overhauled and changed all the time. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Order of evaluation of struct initializers
There is code in the compiler explicitly making sure initializers run in source order, and I expect it will stay that way. So I guess this should be mentioned in the documentation as being something you can rely on. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] idea for Rust playground - seeking comments
See also http://codemirror.net/mode/rust/ . Unfortunately, the syntax has changed massively since I wrote that highlighting mode. On the bright side, I believe the syntax became somewhat more regular, so (though I'm not sure about this) a lot of the complexity in the highlighter (and believe me, it is complex) might no longer be needed. Best, Marijn On Fri, Feb 1, 2013 at 10:51 PM, Dean Thompson wrote: > Rust Dev, > > Pablo Fernandez and I are planning to build a simple "Rust playground" -- a > site where people can try running small Rust programs and then record > examples of working or broken Rust code. We wrote down our current strawman > approach at https://github.com/rusthub/rustpad . We would greatly value > feedback from this group before we begin. > > Dean > > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev > ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: All extern "C" functions are unsafe
> > The question I guess is how often this situation comes up. Is it just > libmath? Or is this sort of thing extremely common when doing bindings? > Extremely common. I'm somewhat appalled that the blanket 'all C functions are unsafe' idea is even being considered (and enthusiastically supported). Yes, C code can segfault and do other nasty things if you call it incorrectly. But wrapping every call to a C function in an unsafe block will dilute the 'red flag' role of unsafe blocks to the point of making them just painful noise, and wrapping the C functions themselves in a wrapper function to make them safe is, in most cases, a wax nose -- the wrapper will not be able to guarantee that the call won't go wrong, so no safety is added. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why does Rust compile slowly?
Regardless of all that, yes, the Rust compiler *is* slower than the Go compiler. Not a factor 25, when you make a fair comparison, but still quite a lot slower. This has two reasons. Firstly, the Go language has partially been designed with compiler speed in mind. It is a simple language, compared to Rust, and thus the compiler simply has to do less work. Secondly, Rob Pike has probably implemented more compilers than all of the Rust team combined, so there's the issue of the Rust compiler simply not being written as cleverly as the Go compiler. This second factor can, and will, be mitigated in the future as the language stabilizes and the compiler gets streamlined further. The first issue means that Rust will probably never compile quite as quickly as Go, because it trades developer ergonomics for compilation time. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Proposal/request to precede variable binding with "let" in destructuring pattern matching and closures
> Are you saying that struct destructuring also occurs outside of > match constructs, as a stand-alone assignment statement? Yes, he is, and that fact is one of the major constraints on what patterns may look like. The same pattern syntax is used in regular assignment and alt matching. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] passing by mutable ref
I agree that this shouldn't be allowed. A nullary variant name is not an lvalue. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] method calls vs closure calls
How would one take the value of a method? I think Patrick's -> proposal, or some variation thereof, is preferable, in that it uses obviously different syntax for the different concepts, and is less likely to confuse people. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] In favor of types of unknown size
I must say I prefer Graydon's syntax. `[]T` sets off all kinds of alarms in my head. I have no strong opinion on dynamically-sized types. Not having them is definitely a win in terms of compiler complexity, but yes, some of the things that they make possible are nice to have. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] iter library
> Sorry if I didn't make my purpose clear. The wrapper type is to distinguish > the different modes of iteration. What Joe meant is that you could simply write multiple impls on the same type with different names for the various modes of iteration. impl of iter for maptype { ... } impl iter_keys of iter for maptype { ... } impl iter_vals of iter for maptype { ... } You could then do 'import map::iter_keys;` at the top of a block to force the key-iterating impl to take precedence there. I think the ergonomics of this kind of trick didn't work out as well as hoped, though. You'd get multiple applicable impl errors when importing `map::*`, and seeing which impl is currently closest in a scope is somewhat indirect and confusing. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] proposal for auto-unboxing and impls
How about intermediate half-unboxed types? (If there's an impl for @X, can you directly call its methods on @@X?) I was going to implement this, but it somehow slipped through the cracks. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] paring back the self type to be, well, just a type
It's not just monads that require parameterized self types. It comes up even in something like a generic collection type, if you want to have a map operator. I agree that the problems you raised are real, but I think giving up on the self type this easily would be a shame. It seems that it wouldn't be hard to take the low-tech approach of simply spitting out a well-defined error when one of the situations you describe occurs. Self types are used only as a kind of templates that are filled in when an impl implements an iface. They don't leak into the type system in general, as far as I can see (granted, I can't see all that far, for I am not a type theoretician). Best, Marijn On Fri, Apr 13, 2012 at 12:52 AM, Niko Matsakis wrote: > On 4/12/12 2:08 PM, Dave Halperin wrote: >> >> I'm not advocating either way on this in terms of the complexity tradeoff >> for adding a kind system, just pointing out that it's what you'd need to >> make the current system work and it's not completely crazy to want that >> flexibility out of the type system. > > > Yes, this was one use case that the self type was intended to model (though > not the one that I think will come up most often). I don't think this is > crazy by any means, but right now our type system has no notion of > (Haskell-style) kinds and it'd be a big change to add them. > > It's possible that the self type should be yanked altogether, but it's come > in handy for me many times, but always in its simpler incarnation of "the > type of the receiver" rather than "the type function defined by the current > iface". > > In any case, I spent some time trying to adapt the iface system---in any > form!---to writing generic monadic code and I decided it's just not a very > good fit. There are two major hurdles. > > First, we have no good way to define a "return" function (though perhaps we > could add static or class methods to ifaces). > > Second, and this is more major, we define monadic implementations for some > concrete type and we should be doing it for all types. In principle, > something like > impl of monad for option { ... } > seems like it does what we want, but it also permits things like: > impl of monad for option { ... } > for which there is no clear mapping from which to derive the self type. I > think to do this correctly, we'd rather write something like: > impl of monad for option { ... } > which would also fit with the "kind" notion of Haskell: here the type being > implemented for has kind * => * and so does monad. > > Of course, we would also need to be able to write things like: > fn mapM( > a: [A], > b: fn(A) -> M) -> M<[B]> { ... } > Here the parameter M is bound to some (* => *) type constructor for which > monad is defined. > > I am not opposed to adding such capabilities at some point. But they don't > feel like burning issues to me right *now*. > > > > Niko > ___ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] read file line by line
> Isn't it possible to pass str::trim directly to vec::map? It the indirection > through the block really needed? Currently it is, due to argument modes (map takes a function that expects its argument by-reference, str::split takes it by value). We're hopeful that we've found a way to get rid of this restriction, once the region work is more complete, but it might take a while before all that is implemented. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] building on SunOS, regex
> 'do' is the German abbreviation. Dutch, too. I guess my brain momentarily flipped back to my native language when typing out these abbreviations. Thanks for fixing that. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Update: break/cont/ret in blocks
> Yes, I think vec::iter() should be removed eventually. Say you happen to have a top-level function that you want to apply to all elements in a vector. It doesn't return bool, so vec::each can't be applied to it. vec::iter is useful there. Though maybe this could be some adaptor function built on top of the iter library instead, so that we only have to write it once, rather than for every iterable type. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Update: break/cont/ret in blocks
> True. But it's not clear to me why you would use vec::all() for the loop > function unless you wanted to know whether you broke out of the loop or not > (in other words, if you don't want to see the result, don't use vec::all()). Sure. But now we have three variants for almost the same thing -- `vec::iter` to iterate without breaking, `vec::each` to be able to break but not return a result, and `vec::all` to get a result value. This seems excessive. Anyway, the current implementation does what you wanted, and I'm not about to change it, so rest easy. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Update: break/cont/ret in blocks
> One question: does the for loop generate > a return value? Is it just whatever the function itself returns? Correct. I'm not 100% sure this is desirable yet -- it's more flexible, which is good, but it also means that if you, for example, use vec::all as your iterator, you'll need a semicolon after the loop, or you get a type error. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Update: break/cont/ret in blocks
Hi list, I've pushed a series of patches that implement an alternate `for` loop syntax -- when the `for` keyword is followed by a block-style call ({||}-block as last argument, outside the parentheses), the block is treated specially: it must return (), but the function argument that it is passed to must be a function type that returns bool. The idea is that this is used to call iterators that stop iterating when their block returns false. An implicit return value of true will be wired into the block, and any instances of `cont` will make the block return true, break will make the block return false. See [1] for some test/example code. I've added vec::each, str::each, and list::each functions for use with this construct. They are expected to be replaced by something more refined (the iter library, probably) down the line. When the block in a `for` loop like this contains a `ret` statement (which are now disallowed in regular blocks), it will cause a return from the outer function. It does this by closing over its parent's return pointer and a flag that it sets when returning, which the outer function checks when the call returns. All this only happens when an actual return is present, so you don't pay for it when you don't use it. I've replaced a big chunk of the for loops in the codebase with `for vec::each(v) {|elt| ... }` constructs. This produced a small slowdown in our cycle times (a little over 1%), which is expected, since more inlining and optimization will be needed on the side of LLVM to pummel these into tight loops. Small benchmarks show that the performance of these new-style for loops in the same ballpark, but not the same as, the performance of the primitive for construct (~30% slower for tight, long loops). I expect we'll be able to squeeze out a bit more by making vec::each more optimizable. This was all more or less foreshadowed in the discussion of bug #1619 [2], but (as usual) I took some liberty in the implementation. Comment here if you feel something should be done differently. If there are no serious objections, I'd like to remove support for the old for syntax soon. [1]: https://github.com/mozilla/rust/blob/master/src/test/run-pass/ret-break-cont-in-block.rs [2]: https://github.com/mozilla/rust/issues/1619 Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Return in block functions
See issue [1] for some discussion. The reason was that A) people are bound to expect ret to return from the outer function, which we don't support in most cases, and B) I am in the process of adding a case (for loops on top of blocks) where we *do* support returning out of the outer function from a block, and treating ret differently in different kinds of blocks seems like a bad idea. When going over the existing code that was using ret in blocks, I did find two cases that had to be transformed with a big, right-drifting if, but the rest were loops that would have benefited from proper ret/cont/break support. So yeah, it's not all roses, but I'd argue that huge blocks aren't very good style, and they might benefit from being factored into a few top-level functions. [1]: https://github.com/mozilla/rust/issues/1619 Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] ACL proposal
Looks good on the whole. I guess there'll also be a way to change the default visibility per-module? It might become tedious, when exporting a bunch of things to a specific submodule, to repeat the path for every item. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] LLVM-MC PE/COFF overflow bug (was Re: Some reductions)
I can't thank you enough, Graydon! This would have taken me at least a week to figure out. I'm about to land the full monomorphization code, and finally get rid of the daily ritual of merging my hugely invasive branch with changes to master. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Some reductions
Hi Graydon, Thanks for digging into this so deeply. This probably also explains why the non-optimized build currently fails on Windows (#959) -- it simply generates binaries that are too big. The prospects are looking a little bleak, I guess. Debugging linkers sounds like it'll get hairy. Maybe, as a temporary workaround, we could try finally splitting off the syntax/ part of rustc into its own crate? Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] a proposal for break, ret, and cont
I was actually thinking there wouldn't have to be a special may_return type at all. The returned value can be an option, and return can store to that and then break. Code after the call to the iterator then checks for a `some` value in the return slot and, if found, returns it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] datetime module and some questions
> Just to be clear, do you mean a function outside the iface and impl? Yes, that's what I meant. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] datetime module and some questions
> It wasn't the cast that felt funny to me, it was the role of 0_u32 in the > expression. Its only purpose is to give access to the date impl over u32 > which is ok, but I'm used to having something like class methods for that. Right. As I said, just use constructor functions with different names. We may end up supporting this directly in our class system at some point, but that seems an easy enough workaround. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] datetime module and some questions
> let d = (0_u32 as date).from_str("2001-04-01"); There's no reason to cast to an iface just to call a method on a value. 0_u32.from_str("...") should be equivalent. If you want to have different from_str constructor functions, though, just give them different names instead of using a kludge like this. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] type holes and identifying immutable memory
I feel that I simply don't have the type-theoretic background to say anything definite about this. I'm going to change my stance from 'grumbling darkly in the background' to 'I guess you guys know what you're doing, I'm not objecting'... > hopefully today I can come back with some data about how disruptive this is > to the existing codebase. Right. This is important. If a change end up introducing a lot of awfulness in existing code, that should be a reason to re-think it. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Addressing Dan's bug through immutable memory
> C++ has the same restriction. In practice I've found that it rarely comes > up. Obviously, since const field are rare in C. In Rust, one rarely uses a record type that doesn't have immutable fields. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Addressing Dan's bug through immutable memory
> Yes. What would be legal would be: > > let x = @{a: 10}; > x = @{a: 20}; That seems a rather heavy-handed restriction. > No, it is legal to do `f(foo.x)` but, depending on the type of `foo.x`, > `f()` might be restricted in what it can do with the reference. For > example: How about this: let x = @{mutable y: 10}; let f = fn@(u: int) { x.y = 20; log(error, u); } f(x.y); // Where f's arg is passed by reference, whichever notation you'd use for that ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] RFC: Addressing Dan's bug through immutable memory
Help me understand -- does this mean 'let x = {a: 10}; x = {a: 20};' would be illegal (assigning to non-assignable type)? Also, you only mention pattern matching, but function calls also create references to the arguments. Would it be forbidden to do f(foo.x) where x is a mutable field? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] bind syntax change proposal
First, I like this a lot. I think applying it to operators as well is definitely a good thing. I don't feel strongly about these closures needing to copy the bound values. If you consider them a syntax for currying, one would expect them to copy, but you could also look at them as a shorthand for block/lambda syntax, in which case not copying makes perfect sense. The difference might be moot, actually, since fn@ will copy anyway, and blocks don't escape the call that uses them mutation of the closed over variables will rarely be an issue. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] libuv updated
>> cd src/libuv && git checkout master && git pull --rebase Thanks! You saved me at least ten minutes of confused stumbling. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Proposal: rename sequence concatenation operator to ++
You're right that the impls can be static, in which case interfaces don't enter into it. Also, method names can overlap in Rust (unlike in Haskell) without causing conflicts. So I guess this is not a direct issue. And yes, I do intend to implement support for super-interfaces, they seem to be useful in a lot of situations. Given all that, I'd still like to rename the vector append operator. I think it'd be an improvement in readability. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] A couple of tweaks to make typeclasses easier?
> (1) Typeclass imports become "import impl". So you'd write "import impl > driver::diagnostic::handler" where you'd write "import > driver::diagnostic::handler" today. This way, when you look at a method call > and you don't know where it's coming from, you just grep for "import impl" > and look at all the implementations in scope. It can often be pleasant to have impls included in a * import (but then, it is also occasionally not what you want). Similarly, it is currently very convenient to name a type and an impl with the same name, so that importing it gets you both the type and its methods. Maybe we can somehow tweak the syntax to also allow a form that imports both impls and other things? > (2) Change method calls to '->', like C++, Perl, and PHP. That operator is > free and it has precedent. And getting away from overloading the dot worked > well when we changed module access from '.' to '::'. I considered this when I did the first implementation. I figured that simply giving record field access precedence was good enough, but the readability argument is valid. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Proposal: rename sequence concatenation operator to ++
> What about an add interface? That works, but doesn't provide the conceptual simplicity of a number interface, and if you want to write a generic over any numeric type, it could end up taking a type parameter. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Proposal: rename sequence concatenation operator to ++
Currently it is simply '+'. The thing that prompted this is issue #1520 -- operator overloading. Delegating + on non-builtin-numeric types to a `num` interface that implements methods add/sub/mult/div/rem/neg methods seems elegant, and similar to Haskell's approach. Vector-concatenation + messes everything up though, since vectors can't meaningfully implement the full num interface. In general, it seems preferable to have operators mean a single thing. The code in the compiler that handles + is often quite clumsy, precisely because two very different things have to be dealt with. I briefly floated the idea on IRC to just get rid of a concat binop altogether, and use library calls for this, but it seems people like their concatenating operator, so ++ seems a good choice (it has something of a precedent in Haskells list append operator). Those who oppose, start arguing. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] The obj system is no more
So I've always had a difficult relationship with the obj system, or rather its implementation. I couldn't help grinding my teeth every time I ran into a special case for obj values in the trans pass or had to scroll past some long, ugly block of code for the ast::expr_anon_obj case in some code. Now that we have a viable alternative to objs, and no one objected to removing them, I jumped at the chance and converted all uses of objs to some other approach -- and finally, earlier today, removed support for the obj system from the compiler completely. May it rest in peace. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] tutorial on interfaces: bounded type parameters
> Note the phrase "aren't known at compile time." That reads as if bounded types > offer runtime polymorphism. (They don't, do they?) They do. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] CSV implementation
> I can understand the need for an implicit copy when I pass 'x' to > str::from_chars. However, in the 'inquote' alt branch the copy seems to be > triggered by the access to 'st.quote'. This has to do with the reference safety checker. As soon as you refer to `st` again the checker can no longer guarantee that the `x` reference, which points at a mutable field of `st`, is still live. If you flip the statements around so that `x` is not used after `st`, the warning (and the copy) will go away. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interfaces!
> |// This implements an interface `iter_util` for vector types Ah, I see what you mean now. I've updated the wiki page. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interfaces!
> If I write "impl foo for bar" does that define an impl > named `foo` with no interface, or an impl of the interface `foo`? No interface. > In that case, I write "impl of foo for bar" to get an impl of > the interface `foo` named `foo` for the type `bar`? Correct. How is this inconsistent? There's an optional `of` clause to specify the interface. As an abbreviation, you can leave off the proper name when you want to use the name of the interface (and you specified one). ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Interfaces!
Interfaces and implementations are mostly working now. They aren't snapshotted yet, and there are some details such as binding methods that don't work yet, but there should be enough implemented to play with. Please file any bugs that you find in this, and assign them to me. A description of the syntax and semantics can be found at https://github.com/graydon/rust/wiki/Interfaces Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Documentation
I agree with what Matt suggested on IRC -- that non-HTML docs mostly don't matter anymore. Markdown's syntax rules are an abomination, but in practice their poorly thought-out corner cases don't really get in the way much. It has 'won' as far as HTML-near markup languages go, and almost every programmer is fluent in it. > - A tutorial written in hand-extended markdown and processed > by hand-written javascript The tutorial is actually standard markdown, with the addition of using the definition list extension (which is supported by most parsers), and doing some post-processing on code blocks to syntax-highlight them and to remove some magic directives to make it possible to execute them (thus making it easy to keep it in sync with the actual compiler). This code post-processing is completely orthogonal to the markup format we use -- something like it would have to happen in texinfo as well. (The choice of JS for the rendering script was prompted by the fact that we already have a very good Rust highlighter in JS -- the CodeMirror mode I wrote). Integrating markdown in rustdoc seems like a very good idea. In general, my vote is for more markdown. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] syntactic sugar for blocks in expressions
My first reaction is 'oh god no! that complicates the rules even more!'. But then I remembered how frustrating it is to work out a proposal and have it shot down for vague knee-jerk reasons like that. So, eh, let's just try this for a while and see whether it causes more confusion than the rules we have now. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] unicode support and core
> I'm also curious what people think are "the important parts" of unicode. Character classification is very important, and should be in core I think (if only to encourage people to actually use it instead of rolling their own... badly). Encodings are something people will occasionally need, but a much less important thing. This doesn't have to be in core, I think. (And, if I understand correctly, much of libicu is encoding tables.) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
> Yeah. One thing that concerns me about that is that it means we lose the > ability to write rebind-the-variable functional-style code: Oh. You'd make this apply to irrevocable patterns as well? Or do you intend to get rid of the restriction that let patterns are irrevocable? In the second case, I think I'd prefer a 'you can shadow anything, except consts and tag variants' rule to a blanket 'no shadowing' one. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] names needed for function types
> I wasn't saying the implementation sounded freaky. I was just imagining > looking at a 30,000 line Rust source file with large fn definitions and > trying to figure out whether each one is a block with interesting side > effects through the mutable closure or not. They don't become closures. They just can be passed to functions that expect closures. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] names needed for function types
> The idea that a fn (no closure) could implicitly turn into a block (mutable > closure) seemed freaky when I read the tutorial. There is no actual allocation going on -- the function pointer is paired with a null environment pointer, and that's the closure. You pay nothing, and since a (non-closing) fn can't do anything that a closure couldn't do, I'm not sure why you'd call this freaky. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
> Marijn's note on the wiki[1] about this says he is not a fan. Is this still > true? Is the opposition strong or weak? I'm still not optimistic. I think we'll want to extend pattern matching to also handle matching against constants and maybe even local variables. So probably the rule would end up being that you can't shadow something with a pattern binding. I'm okay with trying that and seeing how it works out, but I *am* worried that it'd introduce a new problem -- the set of names that you can bind will be much reduced, and adding something somewhere up the scope chain will invalidate code further down. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Fwd: minor things that annoy you about Rust?
> and there'll always be that one jerk on your team who runs their literals > together without the separator. *raises hand* But seriously, I think that if our approach to type inference supported it, inferring the type of literals (with warning for overflows) would be great. But it doesn't -- or rather, it doesn't to the extend where the result would be pleasant to program with -- so I'm okay with just living with the suffixes. I do prefer 'u8' to 'b' (or similar), simply because it's easier to remember. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
Here's another one: The fact that, when changing a tag variant, you have to update every single place that matches against it. We might want to revisit the idea of named variant args, that you match by name, so that A) you can leave off all the '_' placeholders, and B) you only need to update your patterns when the actual fields you're interested in change. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
> 4. Lack of break, continue, and labels. I know this is a big one but some > loops are difficult to write without. Anything > more than what is there today will be much apreciated. 'break' and 'cont' exist (though without labels, and not able to break out of a block function). ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Proposal: different alt form flavours
This was prompted by the 'minor annoyances thread'. A big annoyance for me is the recurring `_ {}` at the end of alt patterns that fall through. A worse form is `_ { fail "this is a bug"; }` (alt already fails when not matching, with a line number reference to the alt that blew up, so this kind of `fail` statements mostly just muddle up the code). Instead, I propose: // This one falls through without failing alt myoption pass { some(x) { do_something_with(x); } } // This one explicitly says that is is non-exhaustive, and that // it will fail for bad input alt myoption fail { some(x) { ... } } Normal alt would be required to be exhaustive, and give a compile-time error if it isn't. This is more self-documenting (you're explicitly annotating what you're trying to do when writing a non-exhaustive alt), and somewhat more succinct. I'm not terribly attached to those keywords (`pass` and `fail`), would happily hear alternatives. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
> Sorry, I meant wildcard bindings at the top level of a match only. We've been thinking down the road of making binders at the top of a pattern special a few times, but as you say, that'd cause inconsistency and probably make things even more confusing than they are now. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
> 1000-page error messages. These should be solved now. If you're still seeing them, submit a bug with the code that triggers one. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] minor things that annoy you about Rust?
> 2. The dot after the nullary tag. In general I want to write a nullary tag a > LOT > more often than I want to write a wildcard binder, so I feel like this is the > wrong way for this choice to go, but I'll understand if this is a decided > issue > already. I agree the dot is problematic, but I'm *very* skeptical about your assertion that you're writing more nullary tag patterns than binders. At least in the compiler, I think we see at least ten times more binders than nullary tags. > 4. I wish a lot more of the standard library was object-oriented. I realize > this > is somewhat of a slippery slope, but writing 'vec::len(thing)' is less nice > (to > me) than thing.len(). I think that things in the standard library that are > object-like (vec, str, ...) should be objects. This is part of the reason we're implementing interfaces (type classes). > 5. I do not like the mk_foo()/obj foo {} idiom; it forces code another tabstop > to the right. If interfaces work out, they'll probably replace the current obj system. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] runtime libraries and stage1
What I've been doing for difficult snapshots is to temporarily modify the makefiles to do the thing Niko describes (use stdlib and runtime from snapshot for stage1), building the snapshot, and then reverting the changes to the makefile again. It would be nice if this was something that could be simply turned on and off with a single switch somewhere, but my Makefile-fu wasn't strong enough to actually implement it that way. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Emacs rust-mode updated
It now handles blocks better, and should no longer get confused about objects so easily. Get it from https://github.com/marijnh/rust-mode (Don't forget to byte-compile it!) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Semantics/tutorial feedback
Ah, I should have clarified. 'none' refers to the std::option type, which is defined as `tag option { none; some(T); }`. > let x = MyContainer(); > x.insert(3); // now infer that x is really a MyContainer > > How would the compiler infer that? Well, you can't write there, but you can leave off the <> part, and the type parameter will be unified with the type of the 3, and things will Just Work. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Semantics/tutorial feedback
> 1. Supporting the ternary operator "?:" when "if" is already an > expression seems redundant. As a compulsive code golfer, I'm kind of attached to ?: -- but the point about the '?' and ':' symbols being useful for other things is very valid (we're definitely running out glyphs). > 2. Inferring the type of 'x' in "let x = []" is neat, but is this type > of inference a privilege restricted to the builtin types? No. 'let x = none;' also works (and none is defined as a regular sum type in the stdlib). > 3. The subject says semantics but this is really a syntax objection. I > think "3 as float" will ultimately be a language wart Good call. I've been noticing this too -- there are a bunch of special cases in the parser and pretty-printer to work around this. Added to that, the low precedence on 'as' keeps surprising me. I'd be okay with using a different syntax -- though as(3) seems overly ugly. > 4. target_os and similar attributes may seem convenient but I suspect > will have Rust biting off more than it can chew. What version of win32 > does target_os="win32" mean? It is possible for users to define and check against their own flags. I think there is no harm in providing some basic ones in the compiler. > 7. Not sure if this is intentional or an oversight: but it looks like > there's no way to extend a polymorphic data type while maintaining > independent compilation. We're trying to avoid subtyping. We're working on something akin to type classes, which might address your point here. > 8. Having a 'cycle collector' for shared box types seems as bad as > having a garbage collector. I don't know the details of our cycle collector, but I think we can statically determine which types *might* contain cycles, and only run it on those. Most programs won't have any cyclic types in them. > 9. I'm curious as to the justification for making log a builtin > keyword rather than a builtin library. There are plans to add some reflection features that would make it possible to implement log in the stdlib (and allow people to implement and use alternatives). Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] A proposal: No implicit copies
Looks good. I'd like to include immutable records of implicitly copyable types as implicitly copyable. > The primary use case for move mode arguments was to “give away” a unique > pointer: this is now achieved by having the callee simply declare a parameter > of unique type and having the caller move it to them. When doing channel communication or data-structure construction, there'll probably be a lot of calls that are 'giving away' arguments. I fear that requiring callers to annotate every one of them will be cumbersome. How about changing the semantics of by-move and by-copy parameters to simply automatically insert the copy/move annotation into every call? When exactly would you want to have functions with a non-single-word-sized return value not be constructor functions? I still feel we'd be better off trying to make this implicit and not exposing it to the user. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] do we need lambda?
If bind is staying (there was talk of removing it in favour of lambda at some point), I think we can do without lambda. But the concept of shared closures (which is what bind creates) would still be there. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] criteria for core lib
> Actually, now that I stare at it, the no-inlining issue might make the > core/std split a pretty bad idea at this point. When platform limitations stand in the way of proper software design, I think we should be working on circumventing them. Telling people to write monolithic libraries because the linker model penalizes a more modular approach seems very unfortunate. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] criteria for core lib
I agree with your categorization of what should be in core. I'd split the stdlib into different crates though -- most programs don't need json/rope/treemap/etc . We could put them in a standard distribution, as separate crates, or when the package manager is functional, simply rely on that for providing them. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interface / typeclass proposal
> Do you feel (straw-vote) like you'd be sufficiently happy to be able to > override the former group but not the latter? Definitely. > (Also: please say you've no interest in permitting user-defined > operator-symbols with their own associativity and precedence. Right?) This is from my xmonad config: composeOne [ isDialog -?> manageHook defaultConfig, isKDETrayWindow -?> manageHook defaultConfig, return True -?> insertPosition End Newer <+> manageHook defaultConfig ] It seems to work, but I still don't really understand what it says. Let's not go there in Rust. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interface / typeclass proposal
https://github.com/graydon/rust/wiki/Interface-and-Implementation-Proposal ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interface / typeclass proposal
I agree with Graydon that there's probably not much to be gained from overriding copy and send. I think they should look and act like interfaces when specified as type parameter bounds, but the actual implementations should be automatically derived by the compiler (as they are now). For operator overloading, I disagree -- I think we'll definitely want that to implement decent bignum, complex number, or (mathematical) vector types. Yes, people can go crazy and do dumb things with overloaded operators, but people can do dumb things with just about any feature you give them. A pragma to turn it off is probably an easy thing to support. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interface / typeclass proposal
> there's no way to declare that it does without changing the third-party >library's code This is true in classical sealed classes, but not in open typeclasses. You can always declare an implementation of an interface for a 3rd-party datatype in your own module, or in the module that declares the interface. If there really is no connection between the interface and the methods that a module happens to implement, the chance that they will coincidentally match and implement the same protocol is very small anyway. A wrapper/adapter impl is extremely trivial to write. I'm still skeptical about monomorphizing all bounded generics. Might work out, but it'll require an overhaul of the compiler and some extensive measurement (for unintended bloat). The first version of this should probably do vtable-passing. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interface / typeclass proposal
Hi Niko, Actually, after I sent this off I realized "... but I didn't really make any good points in favour of nominal interfaces at all". I prefer them because they enforce a much more structured way of thinking. Declaring grab-bags of methods and assembling them into interfaces ad-hoc seems clumsy and, as you mention, error prone --- just because a method has a given name, doesn't mean it actually does the same thing as other methods by that name. Explicitly declaring what interface you're implementing would remove this vagueness. It also makes generating and reusing vtables easier -- most of them would only have to be generated once, and can be exported from the module that declares the category. Once we have categories / instances that depend on another type conforming to an interface, those'll have to be parameterized by the other type's vtable, so things get more tricky (much like our current dynamic tydescs). > - I don't see why every category must declare an associated interface. I > like the idea of *allowing* categories to declare associated interfaces, as > it will lead to better error reporting, but I think *requiring* it is too > much. It implies that the main purpose of a category is dynamic dispatch > and I am not sure that will be the case. I don't really see explicitly declared interfaces as having a lot, specifically, to do with dynamic dispatch. I you're right guess ad-hoc category declarations can be nice sometimes, especially since they allow post-hoc interop with code that wasn't written with any kind of interface in mind. But the latter can already be done by, once you've defined your interface, simply declaring an instance that calls the existing methods. Would you be satisfied with ad-hoc, interface-less methods that can only be called statically? > - I think the term instance ought to be reserved for runtime values You're probably right. But I'm not sure 'category' is much more helpful here. Maybe 'implementation'? (`impl`) > I am a bit > concerned about the definition of comparison and equality because they > really want to have two receiver types. Our == requires both operands to be of the same type. It seems all sane equality implementation have that property. However, there are two receive values, and we definitely don't want to end up writing foo.==(bar) or something awful like that. There are several ways to get around this by doing some surface-syntax-shuffling. But I think eventually we'll want to support both oo-method-style interfaces (written val.method(), used when there is clearly a single receiver), and functional-style interfaces (written method(arg, arg2), used when this is not the case). The resolution for the second type is actually easier to do. x == y could desugar to std::cmp::eq(x, y), or we could define some correspondence between infix ops and function names (which would remove the need for things like std::int::add and std::str::eq) the way Haskell does it. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Interface / typeclass proposal
Hi David, > What would you do with multiple instance declarations that differ by > specificity? For example, one declared on [int] and one declared on [T]. Eventually, we'll have to specify a scoring scheme. The closest import always wins, so you can disambiguate explicitly. If you have multiple interface implementations imported at the same level, I'd make that an error in the first version of this system, but I agree that eventually we'll want specificity rules. > This comes down to the different implementation approaches polymorphism. > Monomorphizing is rare in the ML/Haskell tradition, so type classes with > dictionary-passing is a nice fit. But it's not as clear what happens to type > classes when you introduce specialization. Monomorphizing generics that take interfaces sounds wrong. It is probably a win in some situations, and heuristics can be found to detect such situations, but I doubt we'll want to do in general. (What happens seems quite clear though -- you compile a version of the function with the vtable known at compile-time, so all dispatch becomes static.) > Overloaded arithmetic is definitely a pleasant aspect of Haskell's type > classes. But they do exploit type inference pretty heavily. For example, > literals have polymorphic types, and expressions can be given different types > based on the expected type of their context. Have you thought about how this > would look in our system, where inference is more limited? If we stick to our current approach (literals have unambiguous types, binops always act on values of the same type), the only new subtlety is that the type checker has to figure out the return type of a method. I think this can be done early enough, but I'm not deeply familiar with our type checker, so I'd have to try and see. > For example, how do we prevent programmers from declaring some things to be > instances of `send` that aren't supposed to be? For `copy`, this is easy -- your `copy` method does a copy, and the compiler has the full type of the arguments when compiling the method body, so it checks, and complains when you implement a copy method on an invalid type. We'll have to introduce some explicit way of checking whether a type is sendable to do the same for `send`. We'll probably have to wire in automatic 'derived' instances/categories for this to be pleasant though, or you'll be forced to implement your own instances for every tag you declare. Or maybe `copy` and `send` will just look and behave like interfaces on the surface, and in fact refer to some built-in magic interface that the compiler handles specially. > And IINM, there are still blockers that are well-established and fundamental, > like stack growth and x64, no? Right, but those have very competent people working on them already (and are progressing really well). Actually, I agree that this isn't something that has any bearing on a first release. Coming up with new neat requirements at the last moment is a sure way to make that release be delayed. But at least having a proposal to point people to when they ask about support for dynamic dispatch would be a plus. (And yes, this will end up on the wiki, but I find that initial discussion is better done in the mailing list.) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Interface / typeclass proposal
Niko proposed categories [1] two weeks ago. I'm happy that we're looking in this direction. Niko's proposal makes interfaces structural. I'm going to argue that nominal interfaces have advantages both in programmer ergonomics and in compilation-model complexity. [1]: https://mail.mozilla.org/pipermail/rust-dev/2011-November/000941.html I'll be sticking rather closely to Haskell's type class system, which has proven itself in practice. If you aren't already enthusiastic about Haskell's type classes, I recommend watching Simon Peyton Jones' talk about them [2]. He goes over the way type classes can be implemented, and shows a number of really cool applications. [2]: http://channel9.msdn.com/posts/MDCC-TechTalk-Classes-Jim-but-not-as-we-know-them (try to skip the first 3 minutes, they might spoil your appetite) Context: I'd like to implement some minimum viable dynamic dispatch system and get rid of our `obj` implementation before the first public release. Something that can be extended later with classes and traits, but for now just allows us to define vtables that accompany types. To recap, Niko's categories look like this: category vec_seq([T]) { fn len() -> uint { vec::len(self) } fn iter(f: block(T)) { for elt in self { f(elt); } } } Having that, you can do import vec::vec_seq; assert [1].len() == 1u; [1, 2, 3].iter({|i| log i; }) Which is statically resolved. Dynamic dispatch (if I understand correctly), would look like this: type iterable = iface { fn iter(block(T)); }; fn append_to_vec(x: iterable, y: itable) -> [T] { let r = []; x.iter {|e| r += [e];} y.iter {|e| r += [e];} r } // Assuming there exists a category for lists that implements iter append_to_vec([1, 2, 3] as iterable, list::cons(4, list::nil) as iterable) That causes the compiler to create two vtables, both containing an `iter` method, and wrap the arguments in {vtable, @value} structures when they are cast to `iterable` (they'll probably have to be boxed to make sure the size of such a value is uniform, and cleanup is straightforward). Alternatively, my proposal looks like this: interfaces could be fixed groups of methods, that are always implemented all at once. // Define an interface called `seq` interface seq { fn len() -> uint; fn iter(f: block(T)); } // Declare [T] to be an instance of seq instance [T] seq { fn len() -> uint { vec::len(self) } fn iter(f: block(T)) { for elt in self { f(elt); } } } The static way to use this would look the same as above. If you've imported `vec::seq` (std::vec's implementation of seq), you can simply say [1].len(). If there is any instance in scope that applies to type [int] and has a method `len`, that instance's implementation is called. If multiple interfaces are found, the one in the closes scope is chosen. If they are in the same scope, or no interface is found, you get a compiler error. Dynamic dispatch works differently. // Declare T to be an instance of the seq interface fn total_len(seqs: [T]) -> uint { let cnt = 0u; for s in seqs { count += s.len(); } count } In this proposal, the seq vtable is not something that get attached to the value by casting it to an interface, but rather acts as an implicit parameter to the function. The cool thing is that we already have these implicit parameters -- they map very closely to our type descriptors, which we are implicitly passing to generics. What would happen, for such a call, is that the compiler notices that the type parameter has an interface bound, so that instead of passing just a tydesc, it passes both a tydesc and the `seq` vtable that belongs to that type. Inside the function, `s` is known to be of type `T:seq`, so the `s.len` call looks up the `len` method in the vtable passed for type parameter T. You can also require type parameter to conform to multiple interfaces, as in `fn foo(...)` -- that requires passing multiple vtables. (Niko: this is the thing you asked about. Turns out it's not hard to do.) It should be noted that this has both advantages and disadvantages compared to the 'wrap by casting to interface approach'. For one thing, it doesn't allow this fn draw_all(shapes: [T]) { for s in shapes { s.draw(); } } .. or at least, it doesn't do what you want, because it requires all arguments to be of the same type, and only passes a single vtable. An extension can be implemented (at a later time), to support this instead: fn draw_all(shapes: [drawable]) { ... } draw_all([my_circle as drawable, my_rectangle as drawable]); The drawable interface, when used as a type instead of a type parameter bound, would denote a boxed value paired with a vtable, just like in Niko's proposal. And the good part: In the case where the interface is used as a type parameter bound, which should cover most use cases, things do not have to be boxed to
Re: [rust-dev] Kind system update
I somewhat share your worries about the cleverness of the last-userule. But my logic for adding it anyway is: A) We need to do thisanyway as an optimization, so B) if we are already doing it, we mightas well remove the burden of explicitly annotating moves from the userto the compiler. I still think an explicit unary move would be auseful addition for allowing people to write more obvious code, but Idon't think the kind checker should complain about copies that arealready going to be optimized to moves anyway. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Kind system update
I pushed the new kind system today. Things to be aware of are: - We now have proper copyability analysis, and resources can be used in saner ways. - The way arguments are passed to tag, object, and resource constructors changed. See my other e-mail to the list. - 'Last uses' of locals (arguments passed in a mode that makes them owned by the function, and local let variables) are now treated specially -- when stored or passed somewhere, they are moved instead of copied. Most importantly, this makes most returning a local or putting it in a data structure more efficient. This is taken into account by the copyability analysis, so that you only get an error when your program actually tries to use a noncopyable local after storing it somewhere. - The kinds are now called 'sendable', 'copyable', and 'noncopyable'. The keywords to mark generic parameters are 'send' and 'copy' (noncopyable is what you get when you don't specify a keyword). - I got rid of the 'implicit shared [copyable] kind for generic functions' thing again. This means you'll once again often forget to add 'copy' and have to add it after the compiler complains. About 40% of the generic functions in our standard library require copyable arguments -- this is more than I expected. Still, over half can operate on noncopyable types. Defaulting to copyable would have an effect similar to the 'const' keyword in C++ -- people forget to think about it when they write generic functions, so when you do need to apply a generic to a noncopyable kind, you'll first have to fix the generic and all generics it calls to have the right kind bound. - Warning about copying of unique types is easy now (it's implemented and commented out at https://github.com/graydon/rust/blob/master/src/comp/middle/kind.rs#L127 ), but it generates an enormous amount of warnings because we're copying vectors everywhere. I think we might as well leave this off until we have non-unique vector types. That's it. I'll write something up in the tutorial early next week. I think the new system is easier to think about and to explain. And the last-use analysis provided a nice speedup by saving us a bunch of copies. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] I added another parameter passing style
I'm sorry. There is now a mode called by-copy, which was needed to make constructors behave sensibly in the face of proper enforcement of noncopyability. By-copy works just like by-move, except that when the passed value is an lvalue, it is copied instead of moved (or, if it is a type that can't be copied, an error is raised). By-copy guarantees that the callee owns the passed argument, and does it in a way that generates as few copies as possible. Tag variant constructors, object constructors, and resource constructors now all take their arguments by copy. Don't worry too much about passing-style proliferation. I think by-copy will turn out to supersede by-move. Once we have warnings for accidental copies of uniques (the code exists, but it won't be practical to turn it on until vectors become non-unique again), there won't be much of a reason to use by-move over by-copy. We'll also be able to remove the user-visible distinction between by-val and by-ref at some point (though we might want to keep that in native functions only). Cheers, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Kind system revision proposal
Kinds are assigned to generic type parameters to determine what a generic function can do with values of that kind. Rust currently has three kinds: - 'unique' types can be moved and sent (all the scalar types, unique boxes with no resources in them) - 'shared' types can be moved, but can not be sent (anything involving refcounted boxes-- @, obj, lambda) - 'pinned' types can be sent, but not moved (this currently applies to resources, anything including resources, and blocks) I'm arguing that this is not a very good system, and that we'd be better off considering 'copying' rather than 'moving' as a property. This was the way the system was originally designed, but when implementing it, Graydon changed to the system outlined above. In private mail, he told me that the reason for this was that we couldn't allow blocks (functions closing over local frames) to be moved. I propose the following alternative, which allows resources to be moved again (*), greatly reduces the awkwardness of declaring types for generic functions, and defines a more specialized approach to safety for blocks (**), and actually help define noncopyability (which the current system doesn't do at all). We'd have the following kinds (better terms will have to be found, but I'm using these for clarity): - 'send,copy' types can be copied and sent (scalar types, unique boxes without resources in them) - 'nosend,copy' types can be copied, not sent (the same as the 'shared' types above, refcounted things) - 'nosend,nocopy' types can't be sent or copied (resources, unique boxes with resources in them, blocks) Contrary to the old kinds, this forms a hierarchy, and the kinds lower in the list can be treated as sub-kinds of those above them (a 'send,copy' value can be safely treated as a 'nosend,nocopy' value). Most generic functions will neither send nor copy values of their parameterized type, so they can safely default to 'nosend,nocopy' without losing genericity. When they *do* copy or send, and the programmer forgets to annotate the type parameter as such, a clear, understandable error message can be provided. Generic types (type and tag) do not seem to have a reason to ever narrow their kind bounds in this system, so (unless I am missing something), they should probably not even be allowed to specify a kind on their parameters. We'll have to define more closely when copying happens. I probably forgot some cases here, but—an lvalue (rvalues are always conceptually moved) is copied when: - It is assigned to some other lvalue with = - It is copied into a lambda closure - It is passed as an argument in an unsafe way (safe argument passing does not copy) - It is used as the content of a newly created data structure (it is not yet clear how tag/resource constructors can be distinguished from other functions for this purpose. maybe they should take their args in move mode, though that would require one to always say option::some(copy localvar), which is also awkward) - It is returned from a function or block It might be useful to consider the last use of a local (let) variable to be an rvalue, since that local will never be referenced again, and it is always safe to move out of it. This will cause most returns to become moves (though returning a non-move-mode argument or the content of a data structure is still a copy). The intention is to only annotate things as a copy where there will *actually* be two reachable versions of a value after the operation. (The translator pass is already optimizing most of the situations where this isn't the case into a move or construct-in-place. This system could move some of that logic into the kind-checking pass.) Block safety will have to be handled on a more or less syntactic level. Values with block type can be restricted to only appear in function argument or callee position, and when appearing in argument position, the argument mode has to be by-reference. This is a kludge, but a relatively simple one (a small pass coming after typechecking can verify it). Given this, we can have a kind-checking pass that actually works, without imposing a big burden on users. Generic functions (and objects, as they currently exist) will have their parameters be 'nocopy,nosend' when no kind annotation is present, which will usually be the right thing. Generic data types will never have to be annotated with kinds. I hope people agree this system is easier to understand than the current one. I also hope I didn't miss any gaping soundness holes. Please comment. *) Resources that can't be moved are rather useless. They can only exist as local variables and never be stored in a data structure. This is why there is currently a kludge in the kind-checking code to allow resources to be constructed into data structures. This is needlessly special-cased, and doesn't really work very well at the moment (you can't, for example, put a resource in a tag value.) **) If the 'regions' design that Patrick and Niko are working on
Re: [rust-dev] First skeleton of a tutorial
I wrote the sections on modules and native functions today, cleaned up some of the existing text, and added pretty syntax highlighting to the code in the HTML output. Still at http://marijnhaverbeke.nl/rust_tutorial Cheers, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] First skeleton of a tutorial
http://marijnhaverbeke.nl/rust_tutorial (I didn't have time to integrate it with rust-lang.net today, and that probably should wait until it's a bit more fleshed out). Please comment. There's a bunch of stuff completely missing for now (tasks, most notably). ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Renaming "tag" and "log_err"
Also relevant here: log_err was originally added as a stopgap temporary solution, with the idea being that logging eventually would be a more primitive operation where you specified both a log level and a message, and there would be a macro that'd help you do this in a more nice-looking way. We have four log levels, but are only using two of them at the moment. Making log polymorphic has removed one reason for making it a macro (the idea was to integrate #fmt), but proper support for more log levels would still be nice. (Tangentially, the standard prelude, if such a thing materializes, would be the ideal spot for such a logging macro.) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Renaming "tag" and "log_err"
> but I suppose it can't be helped unless we really want to > have a std::pervasives module that's imported by default. I've been thinking that something like the Haskell standard prelude (small, guaranteed to always be available) might be nice. It could hold some stuff like the std::option datatype, a print-to-stdout function, and a few other things that are really common in tiny programs. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Renaming "tag" and "log_err"
It might be relevant that (for the same "hello world should be simple" reason) recently added `std::io::print` and `std::io::println` to the stdlib. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Change the syntax for type parameter kinds?
I implemented this today. The rationale for making T represent 'pinned' is that 'pinned' is the broadest category -- all types can be passed to a function expecting a pinned type. I still think that making the default 'shared' is a good idea, but there are downsides -- it's easy to define a generic function or datatype as taking a more narrow type than it really accepts. Maybe we could have the compiler warn in such a case? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The new way to do iteration
> Does this mean that the little code snippet on > http://www.rust-lang.org/ is no longer valid? No, that's a vector for loop. Only 'for each x in myiter() { ... }' was removed. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] The new way to do iteration
> This seems to make the feature not very useful. Is there a way we can get > around this limitation? Why do you say that? It is trivial to get around this limitation, but it seems that block calls like this in expression position would just look even weirder than the form where you have the block inside the parentheses. Compare let sum = reduce({|a, b| a + b}, myseq) + 2; let sum = reduce(myseq) {|a, b| a + b} + 2; Do you prefer the second? I figured this would just be a trick to make statement-style loops look better. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Change the syntax for type parameter kinds?
Opened https://github.com/graydon/rust/issues/1067 for this. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Change the syntax for type parameter kinds?
At least two people have confused @T with a boxed type in the past weeks. Even me, who really should know better at this point, occasionally misinterpret some code because of the similarity between the two. The same probably goes for ~T. I think we should change the syntax. It can be a little more verbose, I think, as long as it doesn't resemble other type-related syntax. I'd also support making 'shared' the default kind for type parameters. It is usually what you want. Proposal: 'pinned T' and 'unique T' for pinned/unique type params. 'T' for shared ones. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] The new way to do iteration
As agreed on in this week's meething, I removed compiler support for iter functions and for-each loops today. Instead, it is now possible to say uint::range(0u, 10u) {|i| log_err i; } my_map.items {|key, val| ... } If an call expression in statement position is followed directly by a block ({| or {||), that block is added as a final argument to the call. For a non-call expression, the expression becomes a call with a single argument, the block. (The reason it only recognizes expressions in statement position---at the top level of an outer block---is that this way, you don't need to terminate a block call with a semicolon. When using higher-order functions in a way that returns a value, you'll have to put the block inside the parentheses as before.) Iterators are now simply functions that take a block as their last argument. They are strictly as powerful as our old iterators, and require much less compiler machinery. An open problem is whether we want to allow break/continue or even returning from the outer function inside a block. (This didn't work for the old iterators either.) Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Why are there &&-signs in my function signatures? (or: update on by-value arguments)
You'll notice that, as of today, Rust is once again more picky about passing functions to higher-order functions. Each argument to each function is marked as either by-reference or by-value, and you can not pass a function expecting a by-value arg (`fn(+type)`) to a higher-order function that wants a by-ref function (`fn(&&type)`). The new system is different from the old (pre-my-alias-overhaul) approach in two ways: - You don't have to explicitly annotate most functions. The compiler chooses a default passing convention (by-value for immediate types -- scalars, box/unique pointers, natives -- and by-ref for everything else). In practice, you only need to add a && in front of the arg name when your function takes something that defaults to by-value, but you need a function that passes by ref. - The 'ownership' of the arg stays with the caller, even for by-value args, so that we can usually avoid having to do a take and a drop on args. I think the result is pleasing. We don't have the constant clutter of ampersands in function signatures, but do get the performance benefits of using an appropriate and efficient passing style for each type. Having to line up passing styles for higher-order functions is a bit of a pain, but no more than it used to be before I started messing with call styles. I hope that at one point we'll monomorphize our generics (generate different version for different types), at which point we could simply make them call the given function in the right style, and remove this burden from the programmer. Best, Marijn ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Task scheduling and optimisation
Another thing that makes iterators-as-tasks not really work is data sharing. You want to be able to share data with your iterator, you can't share data with other tasks. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Removing ty_native
One thing that might make using nominal tags like this awkward is that tags are, currently, always structural, so that they will always be passed by reference. I'm hard at work on making immediates be passed by value again, and I think we really want such natives to also be immediate. Looking into the content of tags to decide whether to make them immediate seems kludgy. Maybe we do need a nominal type that's not a tag after all. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Proposal: Java-style iterators
> Hm? I thought we were assuming {|e| ... } only adheres to a call expression > to its left, is considered "the last argument" to the call. Sure, that solves the ambiguity. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Proposal: Java-style iterators
I'm also fine with this. As for the syntax... > vec::each(v) {|e| ... } This once again produces ambiguity with fail and ret: does 'fail {|e| ...}' mean 'call the function produced by fail with this block', or 'fail with this block as the message'. Can be hacked around, or we can just specify that the second version holds, but it's a wart. ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Parameter passing and native calls
> Not anymore, with the C decl. Can you elaborate on that? > How about what I proposed earlier: the '+' sigil means by-value, the '&' > sigil means by-immutable-reference, and leaving it off has the compiler > choose a sensible default based on the type? That'd work, though it'd be a little obscure (a function fn(T) will always take its arg by reference, even when instantiated with T=int). I guess it's a good stopgap until we decide what to do with monomorphizing. Would passing structural types by value be allowed? How would that look? (Using load/store as we used to do, or passing by pointer with the caller owning the value, or passed by pointer with the callee copying it into its frame?) ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev