Hacker News new | past | comments | ask | show | jobs | submit login

So are these associations (functions and constants) just using the object type as a name space? Or is there something more to it?



In the most basic sense you can view it like that. When combined with the typical behavior of traits it gets more interesting. Say you have some data:

    struct Foo;
Then we can make a trait, that defines an interface that we can give to data later:

    trait Bar {
        const BAR_CONSTANT: i32;
        fn some_function();
        fn some_method(self);
    }
Then we can actually implement that trait for our data:

    impl Bar for Foo {
        const BAR_CONSTANT: i32 = 42;
        fn some_function() {
            println!("foo's associated function, and the const is {}", Self::BAR_CONSTANT);
        }
        fn some_method(self) {
            println!("foo's method, and the const is still {}", Self::BAR_CONSTANT);
        }
    }
Then we can use it like so:

    Foo::some_function();  // foo's associated function, and the const is 42
    let foo = Foo;
    foo.some_method();  // foo's method, and the const is still 42
And now we can take it further. Imagine that you have another piece of data, `struct Qux`. Then you can do the same and `impl Bar for Qux`. And now you can write a generic function like so:

    fn bar_taker<T: Bar>(something_that_impls_bar: T) {
        T::some_function();
        something_that_impls_bar.some_method();
        // And of course we can refer to T::BAR_CONSTANT in here as well.
    }
And call it like so:

    bar_taker(foo);
    bar_taker(qux);
AFAIK, the big deal with associated consts is specifically that it allows generic code like that to refer to different values on a per-type basis.

Here's all this code on the Rust interactive playground if you'd like to poke at it: https://play.rust-lang.org/?gist=60bd64e1b2f52bb91ed0b0cb428...


Thanks for the nice example. I've heard of traits but hadn't read enough to know what they are. Looks like a form of multiple inheritance. The example you gave shows polymorphism via traits. That was helpful to me.


It may be easier to see their significance when they're associated with a trait, rather than a struct.

For a simple example, imagine I've got a trait Number, and every implementation of Number is supposed to have a zero constant. Then I could let that constant be Number::ZERO, and refer to it as such in generic code, with each implementation of Number having a different value for Number::ZERO.


Only that they are members of a trait, so you can use it in Rust's generic programming (bounded polymorphism).


is bounded another word for ad-hoc? I always considered Rust's polymorphism implementation like Haskell's, and AFAIK they call it ad hoc polymorphism.


IIRC, "bound" has more to do with quantification than polymorphism more generally.

There is "parametric" vs "ad-hoc". https://stackoverflow.com/questions/6730126/parametric-polym... has a link to the text of TAPL explaining the difference here.

Rust traits and Haskell typeclasses would be ad-hoc.


That's interesting, I always assumed parametric polymorphism was a requirement of ad hoc polymorphism. I suppose I'm using a more narrow definition. On the opposite end,

Elm for instance, has parametric polymorphism:

type Parametric a = Parametric a

f : (a -> b) -> Parametric a -> Parametric b

f fn (Parametric a) = Parametric <| fn a

but no support for ad-hoc, like you said, in Haskell:

data Parametric a = Parametric a

f :: Ord a => Parametric a -> Parametric a -> Parametric a

f (Parametric a) (Parametric b) = Parametric (min a b)




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: