Just because Any is a trait doesn't mean it doesn't break parametricity. Look at this:
http://static.rust-lang.org/doc/master/src/std/home/rustbuild/src/rust-buildbot/slave/doc/build/src/libstd/any.rs.html#37-63 Because we have `impl<T: 'static> Any for T`, it can be used with *any type* (except borrowed data), including type parameters, whether or not they declare the `T: Any` bound explicitly (which is essentially redundant in this situation). The proper thing would be for the compiler to generate an `impl Any for MyType` for each individual type separately, rather than a single generic impl which is valid for all types. I also think we should guarantee parametricity for safe code and make `size_of` an unsafe fn. Its legitimate uses in unsafe code (e.g. smart pointers) are well encapsulated and don't expose parametricity violations, and I don't believe safe code has a legitimate reason to use it (does it?). On Sun, Feb 2, 2014 at 3:27 AM, Eric Reed <[email protected]> wrote: > I'm going to respond to Any and size_of separately because there's a > significant difference IMO. > > It's true that Any and trait bounds on type parameters in general can let > function behavior depend on the passed type, but only in the specific > behavior defined by the trait. Everything that's not a trait function is > still independent of the passed type (contrast this with a setup where this > wasn't true. `fn foo<A>() -> int' could return 2i for int and spin up a > tetris game then crash for uint). Any just happens to be powerful enough to > allow complete variance, which is expected since it's just dynamic typing, > but there's an important distinction still: behavior variance because of > Any *is* part of the function because you need to do explicit type tests. > > I wasn't aware of mem::size_of before, but I'm rather annoyed to find out > we've started adding bare A -> B functions since it breaks parametricity. > I'd much rather put size_of in a trait, at which point it's just a weaker > version of Any. > Being able to tell how a function's behavior might vary just from the type > signature is a very nice property, and I'd like Rust to keep it. > > Now, onto monomorphization. > I agree that distinguishing static and dynamic dispatch is important for > performance characterization, but static dispatch != monomorphization (or > if it currently does, then it probably shouldn't) because not all > statically dispatched code needs to be monomorphizied. Consider a function > like this: > > fn foo<A, B>(ox: Option<~A>, f: |~A| -> ~B) -> Option<~B> { > match ox { > Some(x) => Some(f(x)), > None => None, > } > } > > It's quite generic, but AFAIK there's no need to monomorphize it for > static dispatch. It uses a constant amount of stack space (not counting > what `f' uses when called) and could run the exact same code for any types > A or B (check discriminant, potentially call a function pointer, and > return). I would guess most cases require monomorphization, but I consider > universal monomorphization a way of implementing static dispatch (as > opposed to partial monomorphization). > I agree that understanding monomorphization is important for understanding > the performance characteristics of code generated by *rustc*, but rustc != > Rust. > Unless universal monomorphization for static dispatch makes its way into > the Rust language spec, I'm going to consider it an implementation detail > for rustc. > > > > On Sat, Feb 1, 2014 at 3:31 PM, Corey Richardson <[email protected]> wrote: > >> On Sat, Feb 1, 2014 at 6:24 PM, Eric Reed <[email protected]> >> wrote: >> > Responses inlined. >> > >> >> >> >> Hey all, >> >> >> >> bjz and I have worked out a nice proposal[0] for a slight syntax >> >> change, reproduced here. It is a breaking change to the syntax, but it >> >> is one that I think brings many benefits. >> >> >> >> Summary >> >> ======= >> >> >> >> Change the following syntax: >> >> >> >> ``` >> >> struct Foo<T, U> { ... } >> >> impl<T, U> Trait<T> for Foo<T, U> { ... } >> >> fn foo<T, U>(...) { ... } >> >> ``` >> >> >> >> to: >> >> >> >> ``` >> >> forall<T, U> struct Foo { ... } >> >> forall<T, U> impl Trait<T> for Foo<T, U> { ... } >> >> forall<T, U> fn foo(...) { ... } >> >> ``` >> >> >> >> The Problem >> >> =========== >> >> >> >> The immediate, and most pragmatic, problem is that in today's Rust one >> >> cannot >> >> easily search for implementations of a trait. Why? `grep 'impl Clone'` >> is >> >> itself not sufficient, since many types have parametric polymorphism. >> Now >> >> I >> >> need to come up with some sort of regex that can handle this. An easy >> >> first-attempt is `grep 'impl(<.*?>)? Clone'` but that is quite >> >> inconvenient to >> >> type and remember. (Here I ignore the issue of tooling, as I do not >> find >> >> the >> >> argument of "But a tool can do it!" valid in language design.) >> > >> > >> > I think what I've done in the past was just `grep impl | grep Clone'. >> > >> >> >> >> A deeper, more pedagogical problem, is the mismatch between how `struct >> >> Foo<...> { ... }` is read and how it is actually treated. The >> >> straightforward, >> >> left-to-right reading says "There is a struct Foo which, given the >> types >> >> ... >> >> has the members ...". This might lead one to believe that `Foo` is a >> >> single >> >> type, but it is not. `Foo<int>` (that is, type `Foo` instantiated with >> >> type >> >> `int`) is not the same type as `Foo<unit>` (that is, type `Foo` >> >> instantiated >> >> with type `uint`). Of course, with a small amount of experience or a >> very >> >> simple explanation, that becomes obvious. >> > >> > >> > I strongly disagree with this reasoning. >> > There IS only one type Foo. It's a type constructor with kind * -> * >> (where >> > * means proper type). >> > Foo<int> and Foo<uint> are two different applications of Foo and are >> proper >> > types (i.e. *) because Foo is * -> * and both int and uint are *. >> > Regarding people confusing Foo, Foo<int> and Foo<uint>, I think the >> proposed >> > forall<T> struct Foo {...} syntax is actually more confusing. >> > With the current syntax, it's never legal to write Foo without type >> > parameters, but with the proposed syntax it would be. >> > >> >> I've yet to see a proposal for HKT, but with them that interpretation >> would be valid and indeed make this proposal's argument weaker. >> >> >> >> >> Something less obvious is the treatment of functions. What does `fn >> >> foo<...>(...) { ... }` say? "There is a function foo which, given types >> >> ... >> >> and arguments ..., does the following computation: ..." is not very >> >> adequate. >> >> It leads one to believe there is a *single* function `foo`, whereas >> there >> >> is >> >> actually a single `foo` for every substitution of type parameters! This >> >> also >> >> holds for implementations (both of traits and of inherent methods). >> > >> > >> > Again, I strongly disagree here. >> > There IS only one function foo. Some of it's arguments are types. foo's >> > behavior *does not change* based on the type parameters because of >> > parametricity. >> > That the compiler monomporphizes generic functions is just an >> implementation >> > detail and doesn't change the semantics of the function. >> > >> >> It can if it uses Any, size_of, etc. eddyb had "integers in the >> typesystem" by using size_of and [u8, ..N]. Anything using the >> "properties" of types or the tydescs *will* change for each >> instantiation. >> >> >> >> >> Another minor problem is that nicely formatting long lists of type >> >> parameters >> >> or type parameters with many bounds is difficult. >> > >> > >> > I'm not sure how this proposal would address this problem. All of your >> > proposed examples are longer than the current syntax equivalents. >> > >> >> The idea is there is an obvious place to insert a newline (after the >> forall), though bjz would have to comment more on that. >> > > > _______________________________________________ > Rust-dev mailing list > [email protected] > https://mail.mozilla.org/listinfo/rust-dev > >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
