Re: [rust-dev] On the use of unsafe

2014-09-21 Thread Cameron Zwarich
On Sep 21, 2014, at 1:27 PM, Evan G  wrote:

> Personally, I feel "safety" generalizes pretty well to "any concept
> that should be called out explicitly as unsafe"--not just memory
> safety.

The difference is that the current uses of `unsafe` are guarding things that 
cause a program to not have a defined meaning (ignoring the fact that Rust has 
no real semantics yet, so arguably no program has a defined meaning), whereas 
these other uses are for programs that have a defined meaning, just not the one 
that was intended.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] On the use of unsafe

2014-09-21 Thread Cameron Zwarich
On Sep 20, 2014, at 11:29 PM, Tony Arcieri  wrote:

> He suggested using unsafe to call out when a SQL query is being made with a 
> raw string.
> 
> On the one hand I really liked the clarity of calling out passing a raw 
> string to a SQL driver as being inherently unsafe, but on the other hand it 
> seems to be semantically different from Rust's traditional sense of what's 
> unsafe.
> 
> Is it ok to extend unsafe to things which are unsafe from a security 
> standpoint, or is this conflating concerns?
> 
> Should there be a standard way to express things which are potentially unsafe 
> from a security standpoint but not necessarily from a memory safety 
> standpoint?

The usual solution to this particular problem in typed languages is to make a 
new type wrapping sanitized strings, use some feature of the language (e.g. 
abstract types or module privacy) to restrict the creation of instances of this 
new type, and expose functions that produce an instance of this type by 
sanitization. I think that this is a better use of the language than using 
‘unsafe’ in a confusing and unidiomatic way.

Rust doesn’t really provide any specific features for security beyond memory 
safety, but it should be possible to extend the language to support things like 
information-flow security, etc.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Implementation of traits in Rust: could it be dynamic?

2014-07-22 Thread Cameron Zwarich
Even if we could do a size/alignment-passing implementation like Patrick 
describes, would be it even be appropriate? It wouldn’t make sense for a 
systems language to transparently switch to a dramatically less efficient 
implementation mechanism without the programmer’s involvement.

Is there any place where an unbounded number of dictionaries at runtime is 
actually appropriate for solving a real problem in Rust?

Cameron

On Jul 22, 2014, at 10:16 AM, Lionel Parreaux  wrote:

> Hi,
> 
> So traits seem to be quite similar to Haskell's classes, being also used for 
> parametric polymorphism. Now, Haskell classes are usually implemented using 
> runtime dictionary passing. In general, code cannot be specialized for every 
> function call, since there may be an unbounded number of instances generated 
> for it, as is explained in this reddit answer: 
> http://www.reddit.com/r/haskell/comments/1ar642/what_type_of_binding_does_haskell_use/c94o2ju
> 
> Knowing that Rust implements traits using monomorphization of code (much like 
> C++ templates), I was curious about how it handled such cases, and tried this:
> 
> struct W {
> f: T
> }
> 
> trait Show {
> fn show(&self) -> int;
> }
> 
> impl Show for int {
> fn show(&self) -> int { 666 }
> }
> impl Show for W {
> fn show(&self) -> int { self.f.show()+1 }
> }
> impl Clone for W {
> fn clone(&self) -> W { W{f:self.f.clone()} }
> }
> 
> fn foo(s: &S, n: int) {
> let w = W{f:s.clone()};
> if n > 0 { foo(&w, n-1); }
> }
> 
> fn main() {
>   foo(&W{f:42i},42);
> }
> 
> 
> It gave me an "error: reached the recursion limit during monomorphization", 
> which... well, that's a possible solution :)
> 
> I'm not sure whether this is a big problem in practice, but I was wondering 
> if it would be possible to switch to some runtime mechanism in cases like 
> this. Maybe we could make a special version of every generic functions, that 
> takes a dictionary at runtime and that would be able to handle types unknown 
> at compile-time. We would switch to this version when monomorphization does 
> not work. It could also allow dynamic linking of libraries with generic 
> functions, or it could be a way to compile some programs (or some parts of 
> programs) much faster.
> I was thinking about, for example, an IDE where generic function calls to 
> types defined inside the files currently being edited use their dynamic 
> version, so that recompile times can be virtually inexistent (like Java). On 
> the other hand, the release build would of course monomorphize as much as 
> possible to make the perf optimal.
> 
> Now the question is: would this conform to the current semantic of 
> monomorphization? Do special things happen during monomorphization that 
> cannot be reproduced at runtime?
> This is the case in C++ (and one of the reasons why C++ templates are so 
> "bad"). Is it the case in Rust, which should already have all the required 
> info (type bounds) before monomorphization?
> 
> I apologize if this has already been discussed. I could not find many 
> satisfying answers by googling.
> 
> Cheers,
> LP.
> 
> 
> ___
> 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] compiling Rust to C?

2014-07-18 Thread Cameron Zwarich
On Jul 18, 2014, at 9:52 AM, Josh Haberman  wrote:
> 
>> The only option when targeting C is to use
>> setjmp / longjmp, but that is going to be pretty inefficient.
> 
> Why do you think of setjmp/longjmp as inefficient? If you use the
> _setjmp/_longjmp variants that don't fiddle with the signal mask, they
> seem pretty efficient to me.
> 
> The bigger problem with setjmp/longjmp to me is that they don't let
> you clean up variables sitting on the stack, as Rust language
> semantics do I believe?
> 
> I can think of a way to do this portably, but it costs two extra
> pointers every time you declare any stack variables. Basically you
> could, every time you declare local variables, make them part of a
> struct that has a pointer to the enclosing local var struct, and a
> pointer to an unwind function. Then when a task fails, traverse this
> list of frames and run the unwind function for each one before calling
> longjmp().
> 
> It's wasteful of stack space (since this is basically duplicating
> unwind info that exists at the system level, like in .eh_frame), but
> it is portable.

This is more along the lines of what I meant. The 32-bit ARM Darwin ABI 
actually uses this form of exception handling, and LLVM has some support for 
it. Unlike DWARF unwinding you incur a cost for every cleanup that you 
register, so it can be quite expensive. Having had to debug issues with it in 
the past in LLVM, I'm not sure I would really trust the codegen to be correct.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Requesting information (about globs, macros, subtyping)

2014-07-18 Thread Cameron Zwarich
On Jul 16, 2014, at 10:54 AM, Gábor Lehel  wrote:

> 3. As far as I'm aware, subtyping in the current language arises only from 
> subtyping of lifetimes. Where is this important? One example was mentioned in 
> [Niko's recent blog 
> post](http://smallcultfollowing.com/babysteps/blog/2014/07/06/implied-bounds/).
>  Where else? Without this subtyping of lifetimes, what would break? How 
> burdensome would it be if one had to use explicit casts in those 
> circumstances?

I’ve been thinking about this a bit recently, so I might as well post my 
thoughts in this thread rather than following up privately with people.

All subtyping in Rust is ultimately derived from the inclusion of lifetimes and 
the contravariance of the &/&mut type constructors in their lifetime parameter: 
a pointer to something that lives longer than ‘a is usable in any place where 
we are using a pointer to something with lifetime ‘a. As far as I know, there 
are only 3 original sources of bounds ‘a <= ‘b for lifetimes ‘a and ‘b:

1) Inclusion of concrete lifetimes, i.e. control-flow regions (currently 
lexical scopes, but soon to be extended to arbitrary single-entry / multiple 
exit regions), in the same function.

2) That if a function is parameterized in lifetime ‘b and lifetime ‘a is a 
concrete lifetime in that function, then ‘a <= ‘b.

3) That the scope of a borrow is always included in the lifetime of its 
referent, e.g. that ‘a <= ‘b in &’a &’b T. This is described by Niko in his 
blog post 
http://smallcultfollowing.com/babysteps/blog/2013/04/04/nested-lifetimes/. This 
rule is different than the first two because it is the only way that a bound 
can be propagated on two lifetime *parameters*, whereas the first two involve a 
concrete lifetime in one of the positions.

This is handwaving a bit, since the specifics of 1) and how these all interact 
in the current lifetime inference (and Niko’s proposed simplification) are all 
relevant in practice, but I hope this is a correct abstraction of the situation.

The simplest question to ask is whether it is possible to remove lifetime 
subtyping entirely from Rust. Unfortunately, this is not possible, because if 
you try to do this (see the Tofte-Talpin region system, which is probably the 
closest thing to pure Hindley-Milner type inference for a region system) then 
you have lifetime variables for local variables in a function caller and callee 
unified, so that a called function is allocating local variables in the 
caller’s lifetime. This means that lifetimes no longer correspond to nested 
stack frames, and you also can’t implement destructors properly (at least in 
any trivial way that I can think of). This is not suitable for a systems 
language.

The next logical question to ask is whether you can eliminate the 
non-invariance of type constructors, since that is how subtyping infects the 
rest of the language.

Since &/&mut are contravariant in their lifetime parameter, the vast majority 
of type constructors get their variance inferred as contravariant in lifetime 
parameters. Most examples of contravariance come from something like this:

struct A<‘a> {
x: &’a int,
y: &’a int,
}

If I have two distinct &int borrows with concrete lifetimes (meaning an actual 
control-flow region in the calling function, rather than a lifetime parameter) 
being used at a construction of A<‘a>, then one of the lifetimes is nested in 
the other. Hence I if ‘a is the inner lifetime and ‘b is the outer lifetime, I 
can coerce the &’b to an &’a and construct an A<‘a>.

What do I lose by this? Well, it only works at the first level, so that 
something like this will fail to type-check:

struct A<'a> { x: &'a int }

fn foo(i: int) {
let a = A { x: &i };
if i > 1 {
let j  = 2;
let b = if i > 10 {
a
} else {
A { x: &j }
};
}
}

There are obvious workarounds here, but in more complex examples they could 
possibly hurt the readability / performance of the program. However, the 
fallout is internal to a single function, since there is no way to directly 
propagate the knowledge that one concrete lifetime is included in another to 
another function (beside the 3rd source of bounds mentioned above. which I will 
talk about below).

You can do similar coercions with the sources of bounds 2) and 3). In 2) one of 
the lifetimes is a concrete lifetime again, so again all of the fallout is 
internal to a single function. However, in 3) there is a new complication. 
since knowledge of the relationship between two lifetimes can actually leak 
outside of the functions where they originate. Here is the example in Niko’s 
blog post on 3):

struct BorrowedCursor<'b, T> {
buffer: &'b [T],
position: uint
}

impl<'b, T> Cursor for BorrowedCursor<'b, T> {
fn get<'c>(&'c self) -> &'c T {
&self.buffer[self.position]
}

...
}

This would still work, because we’re dealing directly with the & type 
constructor, and we coul

Re: [rust-dev] compiling Rust to C?

2014-07-18 Thread Cameron Zwarich
The biggest problem would be probably be handling stack unwinding (IIRC the 
LLVM C backend never tried to handle this either). The only option when 
targeting C is to use setjmp / longjmp, but that is going to be pretty 
inefficient. Alternatively you could just abort instead of unwinding.

Cameron

On Jul 18, 2014, at 12:29 AM, Josh Haberman  wrote:

> Is there any prospect of compiling Rust to C anytime in the mid to near 
> future?
> 
> This would be a really attractive option for anyone who wants to write
> in Rust, but wants the extreme portability of C.
> 
> Actually maybe I should first ask if this is actually a tractable
> problem. Are there technical reasons that would prevent compiling Rust
> into portable C?
> 
> LLVM's C Backend seems to have fallen out of maintenance -- would this
> provide the solution I am looking for, if it were maintained?
> 
> Thanks,
> Josh
> ___
> 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] Syntax sugar: Vec Rc RefCell Box Foo -> Vec>>>

2014-06-29 Thread Cameron Zwarich
This is pretty confusing to me because it’s associative in the opposite 
direction that function application is associative in functional languages with 
automatic currying.

Cameron

On Jun 28, 2014, at 3:48 PM, Benjamin Herr  wrote:

> So, I've been vaguely concerned that types in a less sigil-heavy Rust
> inevitably devolve into what some call "spikey lisp", and tried to come
> up with some more lightweight syntax. Of course, just removing syntax is
> the easiest way to make it weigh less, and it seems like the following
> doesn't actually break the grammar dramatically (only some macros!):
> 
> In parsing a path, if a path segment is immediately followed by an
> identifier, start parsing another type right away and use it as the only
> element of the type parameter list for the current path segment.
> 
> This is fairly limited:
> 
> * It won't work for absolute paths as type parameters
>  (since they'll look like just another path segment)
> * It also doesn't work for non-path types in type parameter lists
> * It doesn't simplify multiple type parameters
> 
> I think that's okay, since it's a simplification that applies well to a
> lot of simple cases, and might still reduce the total depth of `<`, `>`
> nesting in more complicated cases.
> 
> So, for example, the following desugarings would apply:
> 
>   Vec String
>=> Vec
> 
>   Arc RWLock Vec f64
>=> Arc>>
> 
>   Arc Exclusive Vec Box Buffer T
>=> Arc // from libsync
> 
>   RefCell DefIdMap Rc Vec Rc TraitRef
>=> RefCell// from librustc
> 
>   HashMap
>=> HashMap, Vec>>>
> 
>   Add
>=> Add, Complex>
> 
>   std::mem::size_of RefCell String()  // maybe a bit much?
>=> std::mem::size_of::>())
> 
> I've patched that into libsyntax and `make check` passes...
> 
> ... after changing some macros, since it basically means that adjacent
> identifiers parse as a single type (or expression, if we omit `::<>`
> too) and some macros try to match `($x:ty fake_keyword_ident ...)`, or
> have a case for `($x:expr)` and another for `(fake_keyword $x:expr)`, or
> just `($t:ty)*`. Seems like just chomping down on all adjacent
> identifiers makes the parser pretty aggressive...
> 
> Yeah, okay, I don't know if this is really a good idea, and it's
> probably not RFC-worthy at this point, but imo it does make the syntax a
> bit easier on the eyes, and I think that's something we ought to look at
> at some point.
> 
> ___
> 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] Integer overflow, round -2147483648

2014-06-23 Thread Cameron Zwarich
On Jun 22, 2014, at 4:12 PM, Patrick Walton  wrote:

> On 6/22/14 2:12 PM, Cameron Zwarich wrote:
>> For some applications, Rust’s bounds checks and the inability of rustc
>> to eliminate them in nontrivial cases will already be too much of a
>> performance sacrifice. What do we say to those people? Is it just that
>> memory safety is important because of its security implications, and
>> other forms of program correctness are not?
>> 
>> I am wary of circling around on this topic again, but I feel that the
>> biggest mistake in this discussion js that checked overflow in a
>> language requires a potential trap on every single integer operation.
>> Languages like Ada (and Swift, to a lesser extent), allow for slightly
>> imprecise exceptions in the case of integer overflow.
> 
> I believe that it is possible that the overhead of integer overflow will be 
> negligible in the future, and that paper is exciting to me too! But I feel 
> that:
> 
> 1. Integer overflow is primarily a security concern when it compromises 
> memory safety. Quoting OWASP [1], emphasis mine:
> 
> "An integer overflow condition exists when an integer, which has not been 
> properly sanity checked, is used in the *determination of an offset or size 
> for memory allocation, copying, concatenation, or similarly*.”

It doesn’t sound like that definition would consider this bug an “integer 
overflow condition”, but it certainly seems like one to me:

http://minimaxir.com/2013/05/stones-of-jordan/

> 3. The As-If-Infinitely-Ranged paper is research. Like all research, the risk 
> of adopting integer overflow checks is somewhat high; it might still not work 
> out to be acceptable in practice when we've exhausted all potential compiler 
> optimizations that it allows. That risk has to be compared against the 
> potential reward, which is likely to be lesser in Rust than in C because of 
> the reasons outlined in (1) and (2).

Ada adopted a similar model before many of the people working on Rust were even 
born, so the basic idea isn’t research. The researchy aspect of the AIR paper 
is retroactively applying it to C. There are probably some unanswered questions 
regarding aggressive optimizations in the face of this model, but the same goes 
for many other design choices of Rust.

> 5. It's not clear to me that integer overflow cannot be added backwards 
> compatibly: we can lexically scope checked arithmetic in much the same way C# 
> lexically scopes unchecked arithmetic. It's not in line with Rust's 
> philosophy of safe-by-default, but saying that we might introduce a safer 
> opt-in version of Rust in the future strikes me as a fairly pragmatic 
> compromise, and one that is not without successful precedent: for example, C, 
> has, for all intents and purposes, successfully shed the baggage of its 
> "variables without an annotated type default to int" design mistake via a 
> bog-standard compiler warning.

I had to deal with bugs caused by K&R C last year, and ABIs for new 
architectures like ARM64 are designed to be compatible with K&R C, even if it 
complicates the implementation, so I don’t necessarily agree that the removal 
of baggage has been quick.

We can probably correct integer operations later (even if it breaks backwards 
compatibility to some extent), but it’s disappointing that a systems language 
from ~2013 can’t learn from all of the correctness lessons of a systems 
language from 1983.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Integer overflow, round -2147483648

2014-06-22 Thread Cameron Zwarich
On Jun 22, 2014, at 10:00 PM, Daniel Micay  wrote:

> On 23/06/14 12:49 AM, Cameron Zwarich wrote:
>> On Jun 22, 2014, at 9:35 PM, Daniel Micay > <mailto:danielmi...@gmail.com>> wrote:
>> 
>>> An operation that can unwind isn't pure. It impedes code motion such as
>>> hoisting operations out of a loop, which is very important for easing
>>> the performance issues caused by indexing bounds checks. LLVM doesn't
>>> model the `nounwind` effect on functions simply for fun.
>> 
>> It gets easier to optimize if you adopt a less precise model of
>> exceptions. For example, you could pick a model where you preserve
>> control dependence and externally visible side effects, but allow
>> reordering in other cases. This does get tricky if destructors
>> themselves have externally visible side effects that are dependent on
>> intervening stores that can be elided.
>> 
>> This probably requires whole-program compilation with some knowledge of
>> externally visible side effects, or more restrictions placed on
>> destructors than there are currently. It also is hard to make work with
>> unsafe code, since unsafe code might require exact placement of
>> unwinding for memory safety in destructors.
>> 
>> Cameron
> 
> Adding restrictions to destructors sounds like adding an effects system
> to Rust. I think the trait system will get in the way of an attempt to
> do that. For example, should a trait like `Eq` use pure methods? If
> they're not pure, then no implementation can be considered pure in
> generic code. Anything using that generic code can't be considered pure,
> and so on.

We already have a need for limiting what destructors can do:

https://github.com/rust-lang/rust/issues/14875

In the case of optimizations, at least you always have the conservative option 
of preserving the exact ordering of unwinding if you can’t prove that it 
doesn’t matter.

Cameron___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Integer overflow, round -2147483648

2014-06-22 Thread Cameron Zwarich
On Jun 22, 2014, at 9:35 PM, Daniel Micay  wrote:

> An operation that can unwind isn't pure. It impedes code motion such as
> hoisting operations out of a loop, which is very important for easing
> the performance issues caused by indexing bounds checks. LLVM doesn't
> model the `nounwind` effect on functions simply for fun.

It gets easier to optimize if you adopt a less precise model of exceptions. For 
example, you could pick a model where you preserve control dependence and 
externally visible side effects, but allow reordering in other cases. This does 
get tricky if destructors themselves have externally visible side effects that 
are dependent on intervening stores that can be elided.

This probably requires whole-program compilation with some knowledge of 
externally visible side effects, or more restrictions placed on destructors 
than there are currently. It also is hard to make work with unsafe code, since 
unsafe code might require exact placement of unwinding for memory safety in 
destructors.

Cameron___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Integer overflow, round -2147483648

2014-06-22 Thread Cameron Zwarich
On Jun 22, 2014, at 8:52 PM, Patrick Walton  wrote:

> On 6/22/14 8:46 PM, Daniel Micay wrote:
>> It's for faster (but not free) array bounds checking. I don't think Rust
>> will be able to use it because it unwinds on out-of-bounds rather than
>> aborting, and it will be difficult to turn the OS support (perhaps
>> SIGFPE / SIGSEGV on *nix) into well defined unwinding in LLVM.
> 
> GCJ did it. Presumably JavaScriptCore does it too. How?

If you’re referring to JSC’s use of LLVM, IIRC (this is based on conversations 
with some of the people that did it, not looking at the code myself) they added 
support for on-stack replacement via stack maps and traps to a runtime to 
LLVM’s JIT. Failure of bounds checks is just treated like any other failure 
that falls off the optimized path and performs an OSR exit.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] &self/&mut self in traits considered harmful(?)

2014-06-22 Thread Cameron Zwarich
On Jun 16, 2014, at 3:19 PM, Patrick Walton  wrote:

> On 6/16/14 3:17 PM, Cameron Zwarich wrote:
>> I stated the right case, but the wrong reason. It’s not for
>> vectorization, it’s because it’s not easy to reuse the storage of a
>> matrix while multiplying into it.
> 
> Wouldn't most matrices be implicitly copyable (and thus optimized--or at 
> least optimizable--into by-ref at the ABI level)?

Sorry for the super-late reply, but if you reuse the same argument multiple 
times, you will have made multiple copies of it, right? A sufficiently 
optimizing compiler would probably be able to optimize it if everything is 
inlined.

However, that also only applies to dense matrices. Sparse matrices are unlikely 
to be Copy.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Integer overflow, round -2147483648

2014-06-22 Thread Cameron Zwarich
For some applications, Rust’s bounds checks and the inability of rustc to 
eliminate them in nontrivial cases will already be too much of a performance 
sacrifice. What do we say to those people? Is it just that memory safety is 
important because of its security implications, and other forms of program 
correctness are not?

I am wary of circling around on this topic again, but I feel that the biggest 
mistake in this discussion js that checked overflow in a language requires a 
potential trap on every single integer operation. Languages like Ada (and 
Swift, to a lesser extent), allow for slightly imprecise exceptions in the case 
of integer overflow.

A fairly simple rule is that a check for overflow only needs to occur before 
the incorrect result may have externally visible side effects. Ada’s rule even 
lets you go a step further and remove overflow checks from loops  in some cases 
(without violating control dependence of the eventual overflowing operation).

One model like this that has been proposed for C/C++ is the “As Infinitely 
Ranged” model (see 
http://www.cert.org/secure-coding/tools/air-integer-model.cfm), where 
operations either give the result that would be correct if integers had 
infinite precision, or cause a trap. This allows for more optimizations to be 
performed, and although it is questionable to me whether they preserved control 
dependence of overflow behavior in all cases, they report a 5.5% slowdown on 
SPEC2006 with GCC 4.5 (compared to a 13% slowdown with more plentiful checks) 
using a very naive implementation. A lot of those checks in SPEC2006 could 
probably just be eliminated if the language itself distinguished between 
overflow-trapping and overflow-permissive operations. If a compiler optimizer 
understood the semantics of potentially trapping integer operations better (or 
at all), it could reduce the overhead of the checks.

I know that some people don’t want to require new compiler techniques (or are 
afraid of relying on something outside of the scope of what LLVM can handle 
today), but it would be unfortunate for Rust to make the wrong decision here 
based on such incidental details rather than what is actually possible.

Cameron

On Jun 22, 2014, at 9:21 AM, Benjamin Striegel  wrote:

> I apologize for being hostile. As Florian has noted, we're just arguing about 
> the default behavior here. It is my opinion that checked behavior by default 
> will make Rust unsuitable for filling C++'s niche, and send the message that 
> we are not serious about performance.
> 
> 
> On Sun, Jun 22, 2014 at 12:10 PM, Evan G  wrote:
> I don't think I was ever "Railing against the incorrectness of overflow 
> semantics"? I was just pointing out that your (imo pretty hostile?) message 
> about "If you don't require absolute speed, why are you using Rust?" doesn't 
> really ring true. Most C++ programmers don't even require absolute speed.
> 
> ___
> 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] On Copy = POD

2014-06-21 Thread Cameron Zwarich
Another big problem with implicit copy constructors is that they make it very 
difficult to write correct unsafe code. When each use of a variable can call 
arbitrary code, each use of a variable can trigger unwinding. You then 
basically require people to write the equivalent of exception-safe C++ in 
unsafe code to preserve memory safety guarantees, and it’s notoriously 
difficult to do that.

Cameron

On Jun 20, 2014, at 8:49 PM, Nick Cameron  wrote:

> I think having copy constructors is the only way to get rid of `.clone()` all 
> over the place when using` Rc`. That, to me, seems very important (in making 
> smart pointers first class citizens of Rust, without this, I would rather go 
> back to having @-pointers). The trouble is, I see incrementing a ref count as 
> the upper bound on the work that should be done in a copy constructor and I 
> see no way to enforce that.
> 
> So, I guess +1 to spirit of the OP, but no solid proposal for how to do it.
> 
> 
> On Sat, Jun 21, 2014 at 8:00 AM, Benjamin Striegel  
> wrote:
> I'm not a fan of the idea of blessing certain types with a compiler-defined 
> whitelist. And if the choice is then between ugly code and copy constructors, 
> I'll take ugly code over surprising code.
> 
> 
> On Fri, Jun 20, 2014 at 3:10 PM, Patrick Walton  wrote:
> On 6/20/14 12:07 PM, Paulo Sérgio Almeida wrote:]
> 
> Currently being Copy equates with being Pod. The more time passes and
> the more code examples I see, it is amazing the amount of ugliness that
> it causes. I wonder if there is a way out.
> 
> Part of the problem is that a lot of library code assumes that Copy types can 
> be copied by just moving bytes around. Having copy constructors would mean 
> that this simplifying assumption would have to change. It's doable, I 
> suppose, but having copy constructors would have a significant downside.
> 
> Patrick
> 
> ___
> 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
> 
> 
> ___
> 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] On Copy = POD

2014-06-21 Thread Cameron Zwarich
On Jun 21, 2014, at 2:15 PM, Nick Cameron  wrote:

> Ownership does not always work, graphs often appear in programming. When they 
> do, you have to use Rc or Gc to cope. We shouldn't punish programmers who 
> have these problems to deal with. Telling them to use ownership is pointless 
> if your data is not hierarchical. In this situation, we are not encouraging 
> users to use ownership instead of ref counting, we are encouraging them to 
> use garbage collection, even when that is not the optimal solution for their 
> problem.

Rust doesn’t actually have a solution for general graph data structures besides 
“store the vertex data in arrays and pass around indices”. In many cases you 
can’t use Rc/Weak. I think this will be a significant limitation of Rust going 
forward.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Integer overflow, round -2147483648

2014-06-21 Thread Cameron Zwarich
On Jun 21, 2014, at 5:50 AM, Gregory Maxwell  wrote:

> On Sat, Jun 21, 2014 at 5:18 AM, Diggory Hardy  
> wrote:
>> As far as I am aware, using theorem proving tools[1] to provide limits on
>> value ranges is pretty hard and often computationally intensive to do in
>> simple code. I've only seen prototype systems where the user is expected to
>> write full contracts on exactly how every function may modify every value it
>> could, as well as often providing hints to the prover (especially for
>> loops). So I really don't think this is going to help much.
> 
> To be sound is hard to catch lots of cases less so— existing C
> compilers manage to prove enough about ranges to eliminate redundant
> tests pretty often— e.g.
> 
> #include 
> int main(int argc, char **argv){
>  (void)argv;
>  if(argc<16)return 1;
>  argc+=1000;
>  if(argc<8)printf("This code is not emitted by an optimizing compiler.\n");
>  return 0;
> }
> 
> GCC 4.8.2 -O2 manages this example fine and I expect is true for other
> modern optimizing C compilers.

LLVM doesn’t actually optimize this, although it does if you remove the 
`argc+=1000`. LLVM’s range analysis is quite a bit worse than GCC’s. This is a 
fixable problem (the algorithm that GCC uses is pretty simple), but it would 
negatively impact compile time by a small amount.

> This is part of the reason that C's undefinedness has real performance
> implications, as sometimes it can only prove loop iteration counts or
> pointer non-aliasing (both useful for vectorization) when it knows
> that indexes cannot overflow.

You only get a benefit from the assumption that indices can’t overflow when you 
are using signed indices. If you have the loop

int len = …;
for (int i = 0; i < len; i++) { … }

then there are two possible trip counts for the loop depending on whether `len` 
is negative (i.e. whether i wraps or not). I don’t think there is any situation 
where it helps signed arithmetic be more efficient than unsigned arithmetic. 
This is arguably bad code in C/C++ anyways, since the language strongly 
encourages you to use unsigned indices. Rust doesn’t have any analogue of this 
problem, because `uint` is used for indexing and coercions are explicit.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] On Copy = POD

2014-06-20 Thread Cameron Zwarich
On Jun 20, 2014, at 11:06 PM, Nick Cameron  wrote:

> zwarich: I haven't thought this through to a great extent, and I don't think 
> here is the right place to plan the API. But, you ought to still have control 
> over whether an Rc pointer is copied or referenced. If you have an Rc 
> object and pass it to a function which takes an Rc, it is copied, if it 
> takes a &Rc or a &T then it references (in the latter case with an 
> autoderef-ref). If the function is parametric over U and takes a &U, then we 
> instantiate U with either Rc or T (in either case it would be passed by 
> ref without an increment, deciding which is not changed by having a copy 
> constructor). If the function takes a U literal, then U must be instantiated 
> with Rc. So, you still get to control whether you reference with an 
> increment or not.
> 
> I think if Rc is copy, then it is always copied. I would not expect it to 
> ever move. I don't think that is untenable, performance wise, after all it is 
> what everyone is currently doing in C++. I agree the second option seems 
> unpredictable and thus less pleasant.

Copying on every single transfer of a ref-counted smart pointer is definitely 
*not* what everyone is doing in C++. In C++11, move constructors were added, 
partially to enable smart pointers to behave sanely and eliminate extra copies 
in this fashion (albeit in some cases requiring explicit moves rather than 
implicit ones like in Rust).

Before that, it was possible to encode this idiom using a separate smart 
pointer for the expiring value. WebKit relies on (or relied on, before C++11) a 
scheme like this for adequate performance:

https://www.webkit.org/coding/RefPtr.html

In theory, you could encode such a scheme into this “always copy on clone" 
version of Rust, where Rc would always copy, and RcTemp wouldn’t even implement 
clone, and would only be moveable and convertible back to an Rc. However, it 
seems strange to go out of your way to encode a bad version of move semantics 
back into a language that has native move semantics.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] On Copy = POD

2014-06-20 Thread Cameron Zwarich
I sort of like being forced to use .clone() to clone a ref-counted value, since 
it makes the memory accesses and increment more explicit and forces you to 
think which functions actually need to take an Rc and which functions can 
simply take an &.

Also, if Rc becomes implicitly copyable, then would it be copied rather than 
moved on every use, or would you move it on the last use? The former seems 
untenable for performance reasons, since removing unnecessary ref-count 
operations is important for performance. The latter seems unpredictable, since 
adding a second use of a value in a function would mean that new code is 
implicitly executed wherever the first use is.

Cameron
 
On Jun 20, 2014, at 8:49 PM, Nick Cameron  wrote:

> I think having copy constructors is the only way to get rid of `.clone()` all 
> over the place when using` Rc`. That, to me, seems very important (in making 
> smart pointers first class citizens of Rust, without this, I would rather go 
> back to having @-pointers). The trouble is, I see incrementing a ref count as 
> the upper bound on the work that should be done in a copy constructor and I 
> see no way to enforce that.
> 
> So, I guess +1 to spirit of the OP, but no solid proposal for how to do it.
> 
> 
> On Sat, Jun 21, 2014 at 8:00 AM, Benjamin Striegel  
> wrote:
> I'm not a fan of the idea of blessing certain types with a compiler-defined 
> whitelist. And if the choice is then between ugly code and copy constructors, 
> I'll take ugly code over surprising code.
> 
> 
> On Fri, Jun 20, 2014 at 3:10 PM, Patrick Walton  wrote:
> On 6/20/14 12:07 PM, Paulo Sérgio Almeida wrote:]
> 
> Currently being Copy equates with being Pod. The more time passes and
> the more code examples I see, it is amazing the amount of ugliness that
> it causes. I wonder if there is a way out.
> 
> Part of the problem is that a lot of library code assumes that Copy types can 
> be copied by just moving bytes around. Having copy constructors would mean 
> that this simplifying assumption would have to change. It's doable, I 
> suppose, but having copy constructors would have a significant downside.
> 
> Patrick
> 
> ___
> 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
> 
> 
> ___
> 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] Why are generic integers not usable as floats?

2014-06-19 Thread Cameron Zwarich
Not all integer constants can be perfectly represented as floating-point 
values. What do you propose in that case, just a hard error?

Cameron

> On Jun 19, 2014, at 4:02 PM, Matthew McPherrin  wrote:
> 
> This came up on IRC today, and it was something I've wondered in the past but 
> nobody had an immediately good answer either way.
> 
> I think it's fairly inconsistent that these two code samples aren't 
> equivalent:
> 
> let a = 1f32;
>   let b: f32 = 1;
> 
> It's fairly annoying in my opinion to have to occasionally add a .0 after 
> floating point literals.
> 
> Especially since we're getting rid of integer fallback in RFC 30, I think 
> this issue ought to be thought about.
> ___
> 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] Fwd: &self/&mut self in traits considered harmful(?)

2014-06-16 Thread Cameron Zwarich
On Jun 16, 2014, at 3:03 PM, Cameron Zwarich  wrote:

> On Jun 16, 2014, at 2:24 PM, Patrick Walton  wrote:
> 
>> On 6/16/14 1:04 PM, Sebastian Gesemann wrote:
>>> Am 16.06.2014 19:36, schrieb Patrick Walton:
>>>> On 6/16/14 7:32 AM, Sebastian Gesemann wrote:
>>>>> Assuming this RFC is accepted: How would I have to implement Add for a
>>>>> custom type T where moving doesn't make much sense and I'd rather use
>>>>> immutable references to bind the operands?
>>>> 
>>>> You don't implement Add for those types.
>>> 
>>> As far as I'm concerned that's anything but a satisfactory answer. I
>>> really don't see the point of your RFC. If anything, it seems to make
>>> things worse from my perspective. That's why I asked you for some
>>> clarifications. Of course, you don't owe me anything. And I hope you
>>> don't take this personally.
>> 
>> I don't see much of a use case for `Add` without move semantics. Does anyone 
>> have any?
>> 
>> Strings and vectors, perhaps, but I would argue that having to call 
>> `.clone()` on the LHS or RHS (as appropriate) is an improvement, because 
>> cloning strings and vectors can be very expensive.
> 
> This applies to Mul rather than Add, but if you are multiplying matrices then 
> you want the destination to not alias either of the sources for vectorization 
> purposes, so passing by reference is preferred.

I stated the right case, but the wrong reason. It’s not for vectorization, it’s 
because it’s not easy to reuse the storage of a matrix while multiplying into 
it.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Fwd: &self/&mut self in traits considered harmful(?)

2014-06-16 Thread Cameron Zwarich
On Jun 16, 2014, at 2:24 PM, Patrick Walton  wrote:

> On 6/16/14 1:04 PM, Sebastian Gesemann wrote:
>> Am 16.06.2014 19:36, schrieb Patrick Walton:
>>> On 6/16/14 7:32 AM, Sebastian Gesemann wrote:
 Assuming this RFC is accepted: How would I have to implement Add for a
 custom type T where moving doesn't make much sense and I'd rather use
 immutable references to bind the operands?
>>> 
>>> You don't implement Add for those types.
>> 
>> As far as I'm concerned that's anything but a satisfactory answer. I
>> really don't see the point of your RFC. If anything, it seems to make
>> things worse from my perspective. That's why I asked you for some
>> clarifications. Of course, you don't owe me anything. And I hope you
>> don't take this personally.
> 
> I don't see much of a use case for `Add` without move semantics. Does anyone 
> have any?
> 
> Strings and vectors, perhaps, but I would argue that having to call 
> `.clone()` on the LHS or RHS (as appropriate) is an improvement, because 
> cloning strings and vectors can be very expensive.

This applies to Mul rather than Add, but if you are multiplying matrices then 
you want the destination to not alias either of the sources for vectorization 
purposes, so passing by reference is preferred.

Cameron
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Bring Back Type State

2014-06-04 Thread Cameron Zwarich
Is there a canonical example of encoding a state machine into Rust's 
substructural types?

Cameron

> On Jun 4, 2014, at 10:14 PM, Brian Anderson  wrote:
> 
> Thank you for your suggestion, but typestate is not coming back. There is no 
> room in the complexity budget for another major piece of type system, and 
> linear types can serve much the same purpose.
> 
>> On 06/04/2014 10:11 PM, Suminda Dharmasena wrote:
>> Hi,
>> 
>> The initial Type State implementation in Rust was not a great way to get 
>> about it. Please reconsider adding type state like it has been done in the 
>> Plaid language.
>> 
>> Basically you can use traits mechanism to mixin and remove the trait when 
>> methods marked as having state transitions.
>> 
>> Suminda
>> 
>> Plaid: http://www.cs.cmu.edu/~aldrich/plaid/
>> 
>> 
>> ___
>> 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
___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] GADT

2014-06-04 Thread Cameron Zwarich
There are at least two tricky aspects to adding GADTs in Rust:

1) Rust implements parametric polymorphism via monomorphization (duplicating 
polymorphic functions for each type), but GADTs are really only useful with 
polymorphic recursion, which requires a polymorphic function to be applied to a 
potentially unbounded number of types at runtime.

2) The interaction between GADTs and subtyping (e.g determining the variance of 
GADT constructors) is nontrivial.

Cameron

> On Jun 4, 2014, at 8:33 AM, Suminda Dharmasena  wrote:
> 
> Hi,
> 
> It is great you have ADT but can you extend it to have GADTs?
> 
> Suminda
> ___
> 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] Calling a method while iterating over a field of the object

2014-06-01 Thread Cameron Zwarich
It’s difficult to do something better without somewhat breaking the 
encapsulation of your graph type, but you could split G into edge and vertex 
data structures and have the functions that add vertices / edges operate on 
part of . Then given an &mut G, you could reborrow the vertex data and the edge 
data with &mut pointers separately.

This is tricky because not all implementations of a graph interface allow 
separate modification of vertex and edge data, so to exploit this you have to 
expose your representation somewhat.

Cameron

On Jun 1, 2014, at 2:15 PM, Nicholas Bishop  wrote:

> Building an intermediate would work, but it implies extra overhead. If
> this was a large graph instead of just one edge then it could be
> expensive to copy from the intermediate back into the original object.
> Are there any alternatives to consider?
> 
> On Sun, Jun 1, 2014 at 4:48 PM, Cameron Zwarich  wrote:
>> `mut_iter` only gives you mutable references to the elements of the
>> container; it doesn’t allow you to reborrow the container itself mutably
>> inside of the loop.
>> 
>> Cameron
>> 
>> On Jun 1, 2014, at 1:39 PM, Christophe Pedretti
>>  wrote:
>> 
>> and using mut_iter() instead of iter() is not enough ?
>> 
>> 
>> 2014-06-01 22:03 GMT+02:00 Cameron Zwarich :
>>> 
>>> The simplest thing to do is probably to build an intermediate vector of
>>> vertices to insert and then push them all after you are done iterating over
>>> the edges.
>>> 
>>> Cameron
>>> 
>>>> On Jun 1, 2014, at 12:48 PM, Nicholas Bishop 
>>>> wrote:
>>>> 
>>>> I'm looking for a little borrow-checker advice. Here's a reasonably
>>>> minimal program that demonstrates the problem:
>>>> 
>>>> extern crate collections;
>>>> 
>>>> use collections::HashMap;
>>>> 
>>>> struct G {
>>>>  verts: HashMap,
>>>>  edges: Vec<(int, int)>,
>>>> 
>>>>  next_vert_id: int
>>>> }
>>>> 
>>>> impl G {
>>>>  fn new() -> G {
>>>>  G{verts: HashMap::new(), edges: Vec::new(), next_vert_id: 0}
>>>>  }
>>>> 
>>>>  fn add_vert(&mut self, s: &str) -> int {
>>>>  let id = self.next_vert_id;
>>>>  self.next_vert_id += 1;
>>>>  self.verts.insert(id, String::from_str(s));
>>>>  id
>>>>  }
>>>> 
>>>>  fn add_edge(&mut self, v0: int, v1: int) {
>>>>  self.edges.push((v0, v1))
>>>>  }
>>>> }
>>>> 
>>>> fn main() {
>>>>  let mut g = G::new();
>>>> 
>>>>  {
>>>>  let v0 = g.add_vert("vert 0");
>>>>  let v1 = g.add_vert("vert 1");
>>>>  g.add_edge(v0, v1);
>>>>  }
>>>> 
>>>>  for &(v0, v1) in g.edges.iter() {
>>>>  g.add_vert("edge vert");
>>>>  }
>>>> }
>>>> 
>>>> This fails to compile:
>>>> $ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc -v
>>>> rustc 0.11.0-pre-nightly (064dbb9 2014-06-01 00:56:42 -0700)
>>>> host: x86_64-unknown-linux-gnu
>>>> 
>>>> $ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc graph.rs
>>>> graph.rs:39:9: 39:10 error: cannot borrow `g` as mutable because
>>>> `g.edges` is also borrowed as immutable
>>>> graph.rs:39 g.add_vert("edge vert");
>>>>  ^
>>>> graph.rs:38:22: 38:29 note: previous borrow of `g.edges` occurs here;
>>>> the immutable borrow prevents subsequent moves or mutable borrows of
>>>> `g.edges` until the borrow ends
>>>> graph.rs:38 for &(v0, v1) in g.edges.iter() {
>>>>   ^~~
>>>> graph.rs:41:2: 41:2 note: previous borrow ends here
>>>> graph.rs:38 for &(v0, v1) in g.edges.iter() {
>>>> graph.rs:39 g.add_vert("edge vert");
>>>> graph.rs:40 }
>>>> graph.rs:41 }
>>>>  ^
>>>> error: aborting due to previous error
>>>> 
>>>> My understanding of the error is: G::add_vert is being given a mutable
>>>> reference to "g", which means it could do something naughty like clear
>>>> g.edges, which would screw up the loop iteration that is happening in
>>>> main().
>>>> 
>>>> That seems like a pretty reasonable thing to prevent, but it's not
>>>> clear to me how I should restructure the program to work around the
>>>> error. In this minimal example I could copy the code out of
>>>> G::add_vert and stick it directly inside the loop, but that's clearly
>>>> not the general solution.
>>>> 
>>>> Thanks,
>>>> -Nicholas
>>>> ___
>>>> 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
>> 
>> 
>> ___
>> 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
>> 

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] Calling a method while iterating over a field of the object

2014-06-01 Thread Cameron Zwarich
`mut_iter` only gives you mutable references to the elements of the container; 
it doesn’t allow you to reborrow the container itself mutably inside of the 
loop.

Cameron

On Jun 1, 2014, at 1:39 PM, Christophe Pedretti  
wrote:

> and using mut_iter() instead of iter() is not enough ?
> 
> 
> 2014-06-01 22:03 GMT+02:00 Cameron Zwarich :
> The simplest thing to do is probably to build an intermediate vector of 
> vertices to insert and then push them all after you are done iterating over 
> the edges.
> 
> Cameron
> 
> > On Jun 1, 2014, at 12:48 PM, Nicholas Bishop  
> > wrote:
> >
> > I'm looking for a little borrow-checker advice. Here's a reasonably
> > minimal program that demonstrates the problem:
> >
> > extern crate collections;
> >
> > use collections::HashMap;
> >
> > struct G {
> >   verts: HashMap,
> >   edges: Vec<(int, int)>,
> >
> >   next_vert_id: int
> > }
> >
> > impl G {
> >   fn new() -> G {
> >   G{verts: HashMap::new(), edges: Vec::new(), next_vert_id: 0}
> >   }
> >
> >   fn add_vert(&mut self, s: &str) -> int {
> >   let id = self.next_vert_id;
> >   self.next_vert_id += 1;
> >   self.verts.insert(id, String::from_str(s));
> >   id
> >   }
> >
> >   fn add_edge(&mut self, v0: int, v1: int) {
> >   self.edges.push((v0, v1))
> >   }
> > }
> >
> > fn main() {
> >   let mut g = G::new();
> >
> >   {
> >   let v0 = g.add_vert("vert 0");
> >   let v1 = g.add_vert("vert 1");
> >   g.add_edge(v0, v1);
> >   }
> >
> >   for &(v0, v1) in g.edges.iter() {
> >   g.add_vert("edge vert");
> >   }
> > }
> >
> > This fails to compile:
> > $ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc -v
> > rustc 0.11.0-pre-nightly (064dbb9 2014-06-01 00:56:42 -0700)
> > host: x86_64-unknown-linux-gnu
> >
> > $ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc graph.rs
> > graph.rs:39:9: 39:10 error: cannot borrow `g` as mutable because
> > `g.edges` is also borrowed as immutable
> > graph.rs:39 g.add_vert("edge vert");
> >   ^
> > graph.rs:38:22: 38:29 note: previous borrow of `g.edges` occurs here;
> > the immutable borrow prevents subsequent moves or mutable borrows of
> > `g.edges` until the borrow ends
> > graph.rs:38 for &(v0, v1) in g.edges.iter() {
> >^~~
> > graph.rs:41:2: 41:2 note: previous borrow ends here
> > graph.rs:38 for &(v0, v1) in g.edges.iter() {
> > graph.rs:39 g.add_vert("edge vert");
> > graph.rs:40 }
> > graph.rs:41 }
> >   ^
> > error: aborting due to previous error
> >
> > My understanding of the error is: G::add_vert is being given a mutable
> > reference to "g", which means it could do something naughty like clear
> > g.edges, which would screw up the loop iteration that is happening in
> > main().
> >
> > That seems like a pretty reasonable thing to prevent, but it's not
> > clear to me how I should restructure the program to work around the
> > error. In this minimal example I could copy the code out of
> > G::add_vert and stick it directly inside the loop, but that's clearly
> > not the general solution.
> >
> > Thanks,
> > -Nicholas
> > ___
> > 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
> 
> ___
> 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] Calling a method while iterating over a field of the object

2014-06-01 Thread Cameron Zwarich
The simplest thing to do is probably to build an intermediate vector of 
vertices to insert and then push them all after you are done iterating over the 
edges.

Cameron

> On Jun 1, 2014, at 12:48 PM, Nicholas Bishop  wrote:
> 
> I'm looking for a little borrow-checker advice. Here's a reasonably
> minimal program that demonstrates the problem:
> 
> extern crate collections;
> 
> use collections::HashMap;
> 
> struct G {
>   verts: HashMap,
>   edges: Vec<(int, int)>,
> 
>   next_vert_id: int
> }
> 
> impl G {
>   fn new() -> G {
>   G{verts: HashMap::new(), edges: Vec::new(), next_vert_id: 0}
>   }
> 
>   fn add_vert(&mut self, s: &str) -> int {
>   let id = self.next_vert_id;
>   self.next_vert_id += 1;
>   self.verts.insert(id, String::from_str(s));
>   id
>   }
> 
>   fn add_edge(&mut self, v0: int, v1: int) {
>   self.edges.push((v0, v1))
>   }
> }
> 
> fn main() {
>   let mut g = G::new();
> 
>   {
>   let v0 = g.add_vert("vert 0");
>   let v1 = g.add_vert("vert 1");
>   g.add_edge(v0, v1);
>   }
> 
>   for &(v0, v1) in g.edges.iter() {
>   g.add_vert("edge vert");
>   }
> }
> 
> This fails to compile:
> $ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc -v
> rustc 0.11.0-pre-nightly (064dbb9 2014-06-01 00:56:42 -0700)
> host: x86_64-unknown-linux-gnu
> 
> $ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc graph.rs
> graph.rs:39:9: 39:10 error: cannot borrow `g` as mutable because
> `g.edges` is also borrowed as immutable
> graph.rs:39 g.add_vert("edge vert");
>   ^
> graph.rs:38:22: 38:29 note: previous borrow of `g.edges` occurs here;
> the immutable borrow prevents subsequent moves or mutable borrows of
> `g.edges` until the borrow ends
> graph.rs:38 for &(v0, v1) in g.edges.iter() {
>^~~
> graph.rs:41:2: 41:2 note: previous borrow ends here
> graph.rs:38 for &(v0, v1) in g.edges.iter() {
> graph.rs:39 g.add_vert("edge vert");
> graph.rs:40 }
> graph.rs:41 }
>   ^
> error: aborting due to previous error
> 
> My understanding of the error is: G::add_vert is being given a mutable
> reference to "g", which means it could do something naughty like clear
> g.edges, which would screw up the loop iteration that is happening in
> main().
> 
> That seems like a pretty reasonable thing to prevent, but it's not
> clear to me how I should restructure the program to work around the
> error. In this minimal example I could copy the code out of
> G::add_vert and stick it directly inside the loop, but that's clearly
> not the general solution.
> 
> Thanks,
> -Nicholas
> ___
> 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] A better type system

2014-05-31 Thread Cameron Zwarich
FWIW, I think you could eliminate (c) by prohibiting mutation of sum types. 
What case are you thinking of for (e)?

For (d), this would probably have to be distinguished from the current &mut 
somehow, to allow for truly unique access paths to sum types or shared data, so 
you could preserve any aliasing optimizations for the current &mut. Of course, 
more functions might take the less restrictive version, eliminating the 
optimization that way.

Not that I think that this is a great idea; I’m just wondering whether there 
are any caveats that have escaped my mental model of the borrow checker.

Cameron

On May 31, 2014, at 5:01 PM, Patrick Walton  wrote:

> I assume what you're trying to say is that we should allow multiple mutable 
> references to pointer-free data. (Note that, as Huon pointed out, this is not 
> the same thing as the Copy bound.)
> 
> That is potentially plausible, but (a) it adds more complexity to the borrow 
> checker; (b) it's a fairly narrow use case, since it'd only be safe for 
> pointer-free data; (c) it admits casts like 3u8 -> bool, casts to 
> out-of-range enum values, denormal floats, and the like, all of which would 
> have various annoying consequences; (d) it complicates or defeats 
> optimizations based on pointer aliasing of &mut; (e) it allows uninitialized 
> data to be read, introducing undefined behavior into the language. I don't 
> think it's worth it. 
> 
> Patrick
> 
> On May 31, 2014 4:42:10 PM PDT, Tommi  wrote:
> On 2014-06-01, at 1:02, Patrick Walton  wrote:
> 
>>fn my_transmute(value: T, other: U) -> U {
>>let mut x = Left(other);
>>let y = match x {
>>Left(ref mut y) => y,
>>Right(_) => fail!()
>>};
>>*x = Right(value);
>>(*y).clone()
>>}
> 
> If `U` implements `Copy`, then I don't see a (memory-safety) issue here. And 
> if `U` doesn't implement `Copy`, then it's same situation as it was in the 
> earlier example given by Matthieu, where there was an assignment to an 
> `Option>` variable while a different reference pointing to that 
> variable existed. The compiler shouldn't allow that assignment just as in 
> your example the compiler shouldn't allow the assignment `x = Right(value);` 
> (after a separate reference pointing to the contents of `x` has been created) 
> if `U` is not a `Copy` type.
> 
> But, like I said in an earlier post, even though I don't see this 
> (transmuting a `Copy` type in safe code) as a memory-safety issue, it is a 
> code correctness issue. So it's a compromise between preventing logic bugs 
> (in safe code) and the convenience of more liberal mutation.
> 
> 
> -- 
> Sent from my Android phone with K-9 Mail. Please excuse my brevity.
> ___
> Rust-dev mailing list
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev

___
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev


Re: [rust-dev] A better type system

2014-05-31 Thread Cameron Zwarich
When writing an email stating “your programming language isn’t expressive 
enough”, it’s a good idea to include an example program that you would like to 
write that is rejected by the current type system. Then people replying to your 
email can give you some suggestions on how to best achieve your goals in Rust. 
The usual solution to the problem of safely mutating data is to use Cell, but 
we can’t be sure unless you give an example.

You are correct that mutation is only a risk to memory safety after 
deallocation occurs, but in a language with actual sum types this can occur 
when mutating a variable of a sum type to hold a different variant, since the 
storage is reused for a new variant after mutation, invalidating any references 
into the previous data. However, this doesn’t require preventing the mutation 
of things like integer fields of a struct.

The current guarantee (or the projected guarantee, since this isn’t actually 
implemented in all cases) for &mut references is that all accesses (both reads 
and writes) to &mut data occur through access paths derived from the &mut 
reference. This is helpful because the same guarantee holds regardless of type, 
and the guarantee is strong enough to provide race-free accesses to shared data.

Rust used to have an &const pointer type, which was similar to C++’s const in 
that it guaranteed that modifications didn’t occur through access paths derived 
from the &const pointer, but still allowed them to occur through other access 
paths. From what I understand, it was removed to simplify the type system, 
since most of its uses could be replaced with Cell.

In full generality, you could imagine Rust pointers allowing the specification 
of the following information:

1) Specific derived access paths that are unique, similar to the guarantee 
provided by &mut or the internal &uniq today.

2) Specific derived access paths that may be read through this pointer.

3) Specific derived access paths that may be mutated through this pointer.

4) Specific derived access paths that may observe mutations through access 
paths that do not involve this pointer.

Obviously, not all combinations would be sound or even coherent. This system 
would still permit reborrowing and would allow some interesting situations that 
are forbidden today. For example, you could have a vector v of

struct A { a: int, b: Box }

and have an unrestricted number of mutable/const borrows of the path v[].a but 
a unique mutable borrow of v[].b and all derived paths. You could also pass 
partially initialized structs to other functions, knowing that they don’t read 
any of the uninitialized fields.

Would this be a better type system? Well, it would definitely be more 
expressive than the current system, and it wouldn’t even be extremely difficult 
to modify the borrow checker to implement it. However, it would be a dramatic 
increase in user-facing complexity, since shorthand would only take you so far. 
These complex pointer types would have to appear in every function signature. 
They would also leak implementation details of functions and types even moreso 
than Rust already does.

Cameron

On May 31, 2014, at 10:36 AM, Tommi  wrote:

> It certainly feels like a failure of the Rust type system that you cannot 
> have multiple mutating references to the same variable when the variable is 
> accessed only from a single thread. I know the reason for this is to prevent 
> iterator invalidation, but this is too blunt of an instrument.
> 
> Iterator invalidation (as it's known in C++) is a risk to memory safety only 
> when some of the memory that is accessible through an iterator (or a 
> reference) is deallocated. A better type system would make a distinction 
> between those expressions that may deallocate and those that cannot. Then, 
> when multiple mutating references pointed to the same variable, the compiler 
> would disallow only the use of the potentially deallocating expressions 
> through those references.
> 
> If a variable may be accessed concurrently from multiple threads, only then 
> would the current "no mutating references allowed to that variable" -rule be 
> enforced.
> 
> Sorry for the brevity, I'm writing this from a phone and I haven't thought of 
> this issue very thoroughly.
> 
> ___
> 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