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