Re: [rust-dev] Dynamic in Rust
On Sat, Aug 24, 2013 at 9:50 PM, Lindsey Kuper lind...@composition.alwrote: On Fri, Aug 23, 2013 at 8:30 PM, Sebastian Sylvan sebastian.syl...@gmail.com wrote: I'm sure you've all seen it, but C# has something similar but a lot more powerful. Basically, it has support for allowing runtime resolution of types if they are declared as having the dynamic type. But it's even better, the specification for how that resolution happens is defined in a library. This way you can work directly with dynamic values without having to cast them first (e.g. imagine just dotting your way through a JSON document and parse it on-demand). A more recent approach to this kind of thing is F# type providers (http://msdn.microsoft.com/en-us/library/hh156509.aspx and, for instance, http://fsharp.github.io/FSharp.Data/library/JsonProvider.html). Although I'm not especially familiar with them, they seem relevant and interesting. I think they're partially non-overlapping approaches. Type providers is about providing static types to dynamic data. I.e. someone has to write down a schema. C# dynamic is about just dealing with dynamic data on the fly. E.g. you could just open up any old JSON doc and start accessing members. The two approaches are probably used for the same thing, much of the time, but there are occasions where you can't define a static type for something, so having an approach where you can do the runtime checks in a less verbose fashion is nice (which I don't think the F# type providers thing does). -- Sebastian Sylvan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
Hi, On 24/08/2013 01:30, Sebastian Sylvan wrote: I'm sure you've all seen it, but C# has something similar but a lot more powerful. Dynamic in C# is beautiful. It's an amazing way to work with externally controlled data like JSON that is without equivalent in a strongly typed language currently. I'm not sure how much of that Rust can reproduce, but if there is any way it has a strong +1 from me. Regards, Armin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
On Fri, Aug 23, 2013 at 8:30 PM, Sebastian Sylvan sebastian.syl...@gmail.com wrote: I'm sure you've all seen it, but C# has something similar but a lot more powerful. Basically, it has support for allowing runtime resolution of types if they are declared as having the dynamic type. But it's even better, the specification for how that resolution happens is defined in a library. This way you can work directly with dynamic values without having to cast them first (e.g. imagine just dotting your way through a JSON document and parse it on-demand). A more recent approach to this kind of thing is F# type providers (http://msdn.microsoft.com/en-us/library/hh156509.aspx and, for instance, http://fsharp.github.io/FSharp.Data/library/JsonProvider.html). Although I'm not especially familiar with them, they seem relevant and interesting. Lindsey ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
Yes, this would be similar to the `Typeable` type class in Haskell. It queries the vtable-equivalent, which contains stuff like the name of the type and allows doing `typeof(x)`, dynamic casts, etc. This is heavily magical (that is, depends on the hidden internal representation) and properly belongs in the standard platform and not in a user-level library. On Fri, Aug 23, 2013 at 4:40 PM, Niko Matsakis n...@alum.mit.edu wrote: Currently, this is not directly supported, though downcasting in general is something we have contemplated as a feature. It might be possible to create some kind of horrible hack based on objects. A trait like: trait Dynamic { } implT Dynamic for T { } would allow any value to be cast to an object. The type descriptor can then be extracted from the vtable of the object using some rather fragile unsafe code that will doubtless break when we change the vtable format. The real question is what you can do with the type descriptor; they are not canonicalized, after all. Still, it's ... very close. This is basically how dynamic downcasting would work, in any case. Niko On Fri, Aug 23, 2013 at 07:49:57AM +0300, Oren Ben-Kiki wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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] Dynamic in Rust
One question: Do you only want to retrieve the exact type that was passed in, or would you want to be able to extract an impl that matches the type actually contained ? The latter is more difficult to implement (dynamic_cast goes through hoops to check those things), but it is doable if sufficient information is encoded in the v-table. On Fri, Aug 23, 2013 at 5:04 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Yes, this would be similar to the `Typeable` type class in Haskell. It queries the vtable-equivalent, which contains stuff like the name of the type and allows doing `typeof(x)`, dynamic casts, etc. This is heavily magical (that is, depends on the hidden internal representation) and properly belongs in the standard platform and not in a user-level library. On Fri, Aug 23, 2013 at 4:40 PM, Niko Matsakis n...@alum.mit.edu wrote: Currently, this is not directly supported, though downcasting in general is something we have contemplated as a feature. It might be possible to create some kind of horrible hack based on objects. A trait like: trait Dynamic { } implT Dynamic for T { } would allow any value to be cast to an object. The type descriptor can then be extracted from the vtable of the object using some rather fragile unsafe code that will doubtless break when we change the vtable format. The real question is what you can do with the type descriptor; they are not canonicalized, after all. Still, it's ... very close. This is basically how dynamic downcasting would work, in any case. Niko On Fri, Aug 23, 2013 at 07:49:57AM +0300, Oren Ben-Kiki wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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] Dynamic in Rust
That's a really good question. In my specific case, I need the exact same type. But a proper implementation would presumably be able to provide any matching type (I believe the Haskell implementation does this). On Fri, Aug 23, 2013 at 7:17 PM, Matthieu Monrocq matthieu.monr...@gmail.com wrote: One question: Do you only want to retrieve the exact type that was passed in, or would you want to be able to extract an impl that matches the type actually contained ? The latter is more difficult to implement (dynamic_cast goes through hoops to check those things), but it is doable if sufficient information is encoded in the v-table. On Fri, Aug 23, 2013 at 5:04 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Yes, this would be similar to the `Typeable` type class in Haskell. It queries the vtable-equivalent, which contains stuff like the name of the type and allows doing `typeof(x)`, dynamic casts, etc. This is heavily magical (that is, depends on the hidden internal representation) and properly belongs in the standard platform and not in a user-level library. On Fri, Aug 23, 2013 at 4:40 PM, Niko Matsakis n...@alum.mit.edu wrote: Currently, this is not directly supported, though downcasting in general is something we have contemplated as a feature. It might be possible to create some kind of horrible hack based on objects. A trait like: trait Dynamic { } implT Dynamic for T { } would allow any value to be cast to an object. The type descriptor can then be extracted from the vtable of the object using some rather fragile unsafe code that will doubtless break when we change the vtable format. The real question is what you can do with the type descriptor; they are not canonicalized, after all. Still, it's ... very close. This is basically how dynamic downcasting would work, in any case. Niko On Fri, Aug 23, 2013 at 07:49:57AM +0300, Oren Ben-Kiki wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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] Dynamic in Rust
On 8/23/13 8:04 AM, Oren Ben-Kiki wrote: Yes, this would be similar to the `Typeable` type class in Haskell. It queries the vtable-equivalent, which contains stuff like the name of the type and allows doing `typeof(x)`, dynamic casts, etc. This is heavily magical (that is, depends on the hidden internal representation) and properly belongs in the standard platform and not in a user-level library. I had always figured we'd copy Haskell's `Data.Typeable` solution more or less exactly. I think we can do it in a library though, as Niko pointed out; in general we aren't afraid of adding deep compiler-specific magic into our libraries. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
Yes, Rust has a `deriving` attribute one can attach to types (for stuff like `Eq`, `Ord`, etc.). That said, as long as the vtable is already there, I think Rust should do what Haskell is moving to (automatically `derive Typeable`) - that is, automatically place the necessary data in the vtable. Haskell does place a restriction on _using_ the data, though. One must explicitly request the type T has the trait `Typeable` in order to invoke functionality that uses the data. Even though all types implement this trait, this explicitly warns the caller that this function may do strange things. I'm not sure what the right choice would be in Rust here. On Fri, Aug 23, 2013 at 7:44 PM, Danny Gratzer danny.grat...@gmail.comwrote: I guess it's worth pointing out GHC's -XDeriveDataTypeable language extension, this let's the compiler automatically derive the Typeable instance for user defined datatypes. If you want to copy Data.Typeable having something (a macro?) to automagically implemented Typeable goes a long way to aiding usability. I'm not sure if an equivalent to Haskell's `derive` exists in Rust. I'm rather new here :) Cheers, Danny Gratzer ___ 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] Dynamic in Rust
On 8/23/13 9:44 AM, Danny Gratzer wrote: I guess it's worth pointing out GHC's -XDeriveDataTypeable language extension, this let's the compiler automatically derive the Typeable instance for user defined datatypes. If you want to copy Data.Typeable having something (a macro?) to automagically implemented Typeable goes a long way to aiding usability. I'm not sure if an equivalent to Haskell's `derive` exists in Rust. I'm rather new here :) Yes, it's called #[deriving] and is a syntax extension. I was assuming that we'd implement it for `Typeable`. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
On 13-08-23 09:49 AM, Oren Ben-Kiki wrote: Yes, Rust has a `deriving` attribute one can attach to types (for stuff like `Eq`, `Ord`, etc.). That said, as long as the vtable is already there, I think Rust should do what Haskell is moving to (automatically `derive Typeable`) - that is, automatically place the necessary data in the vtable. Every type descriptor has a visitor-glue method written into it, which provides typeable-like structural reflection (std::reflect) on types, but not (presently) efficient type-equality. We'd need to augment it slightly to provide that, but I think it'd be possible. This code is used in fmt! for example to support printing arbitrary values (std::repr). -Graydon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
Interesting - I see std::intrinsics::unstable::get_tydescrT - *TyDescr... Two questions: - Can this be used for a quick type equality check (same pointer = same type)? - How can one invoke `get_tydescrint()` or `get_tydescrT` (when `T` is a type parameter of the current function)? I get a syntax error on the `int` or `T`. On Fri, Aug 23, 2013 at 8:50 PM, Graydon Hoare gray...@mozilla.com wrote: On 13-08-23 09:49 AM, Oren Ben-Kiki wrote: Yes, Rust has a `deriving` attribute one can attach to types (for stuff like `Eq`, `Ord`, etc.). That said, as long as the vtable is already there, I think Rust should do what Haskell is moving to (automatically `derive Typeable`) - that is, automatically place the necessary data in the vtable. Every type descriptor has a visitor-glue method written into it, which provides typeable-like structural reflection (std::reflect) on types, but not (presently) efficient type-equality. We'd need to augment it slightly to provide that, but I think it'd be possible. This code is used in fmt! for example to support printing arbitrary values (std::repr). -Graydon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
On 13-08-23 11:08 AM, Oren Ben-Kiki wrote: Interesting - I see std::intrinsics::unstable::get_tydescrT - *TyDescr... Two questions: - Can this be used for a quick type equality check (same pointer = same type)? No, as I said, it does not support efficient type-equality. We don't normalize all types. You should be able to count on one-way equality at the moment (same pointer = same type) but not vice-versa. - How can one invoke `get_tydescrint()` or `get_tydescrT` (when `T` is a type parameter of the current function)? I get a syntax error on the `int` or `T`. get_tydesc::T(). This is the foo vs foo:: syntax papercut. Gets everyone, sorry. It's the price of using for type parameters rather than []. We need a better error message for it. -Graydon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
On 8/23/13 11:15 AM, Graydon Hoare wrote: get_tydesc::T(). This is the foo vs foo:: syntax papercut. Gets everyone, sorry. It's the price of using for type parameters rather than []. We need a better error message for it. Actually, [] would have the same problem, because of array indexing. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
Got it, thanks. I guess that the TyDescr could be extended in the future to support type equality and other things. In the meanwhile, in my case I'll have the user manually annotate the Dynamic with an (interned) string containing the type name, and pray people don't mess it up. Thanks! On Fri, Aug 23, 2013 at 9:15 PM, Graydon Hoare gray...@mozilla.com wrote: On 13-08-23 11:08 AM, Oren Ben-Kiki wrote: Interesting - I see std::intrinsics::unstable::get_tydescrT - *TyDescr... Two questions: - Can this be used for a quick type equality check (same pointer = same type)? No, as I said, it does not support efficient type-equality. We don't normalize all types. You should be able to count on one-way equality at the moment (same pointer = same type) but not vice-versa. - How can one invoke `get_tydescrint()` or `get_tydescrT` (when `T` is a type parameter of the current function)? I get a syntax error on the `int` or `T`. get_tydesc::T(). This is the foo vs foo:: syntax papercut. Gets everyone, sorry. It's the price of using for type parameters rather than []. We need a better error message for it. -Graydon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
On 13-08-23 11:16 AM, Patrick Walton wrote: On 8/23/13 11:15 AM, Graydon Hoare wrote: get_tydesc::T(). This is the foo vs foo:: syntax papercut. Gets everyone, sorry. It's the price of using for type parameters rather than []. We need a better error message for it. Actually, [] would have the same problem, because of array indexing. Naturally, which is why array indexing (way back when) was foo.(index). But it was a throwaway comment; this is all very much water under the bridge, not in any way suggesting we revisit. -Graydon ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
So, as it turns out, something closely related can be implemented in completely safe rust. (The ideas here are based on http://mlton.org/UniversalType and the presentation of extensible types from my undergrad PL class. The implementation is based on the mlton UniversalType page, but I change the interface to be more like extensible types. If anybody cares, SML code for this is https://gist.github.com/msullivan/6324908.) We can implement a universal type that values of any (cloneable, not containing borrowed pointers) type can be injected to. The catch is that the values aren't actually keyed by the type, but by tags that are generated at runtime. This is sometimes useful (you can distinguish between different classes of values of the same type) and sometimes annoying (you have to manage the tags). The implementation here is pretty clever, but also kind of silly. It would probably actually be better in practice to do something unsafe internally with dynamically generated tag values. mod ClosureUniversal { // A value of universal type is a pair of functions. store will // write the underlying value into the associated tag, while clear // will erase the data in the tag to prevent space leaks. pub struct Univ { priv store: @fn(), priv clear: @fn() } // A tag is a mutable option used as a scratch space to write // into when inspecting a tag. pub struct TagA { priv r: @mut OptionA } pub fn new_tagA:'static() - TagA { Tag { r: @mut None } } pub fn injectA:Clone+'static(tag: TagA, x: A) - Univ { Univ { store: || *tag.r = Some(x.clone()), clear: || *tag.r = None } } pub fn projectA:Clone+'static(tag: TagA, x: Univ) - OptionA { // Cause the value to be written into its tag. If the universal // value was injected with our tag, then it will be in tag.r. (x.store)(); // Read out the value. let res = (*tag.r).clone(); // Clear the value, to prevent space leaks. (x.clear)(); res } } fn main() { use ClosureUniversal::*; // Create some tags let int_tag = new_tag::int(); let str_tag = new_tag::~str(); // Create some universal values with those tags let u1 = inject(int_tag, 5); let u2 = inject(int_tag, 6); let u3 = inject(str_tag, ~hello, world); // Try reading them println(fmt!(%?, project(int_tag, u1))); // Some(5) println(fmt!(%?, project(int_tag, u2))); // Some(6) println(fmt!(%?, project(int_tag, u3))); // None println(fmt!(%?, project(str_tag, u1))); // None println(fmt!(%?, project(str_tag, u2))); // None println(fmt!(%?, project(str_tag, u3))); // Some(~hello, world) // Try out a *different* int tag. let int_tag2 = new_tag::int(); // It can not be used to read things created by the other int tag println(fmt!(%?, project(int_tag2, u1))); // None } (Code is also up at https://gist.github.com/msullivan/6324973) On Fri, Aug 23, 2013 at 11:22 AM, Graydon Hoare gray...@mozilla.com wrote: On 13-08-23 11:16 AM, Patrick Walton wrote: On 8/23/13 11:15 AM, Graydon Hoare wrote: get_tydesc::T(). This is the foo vs foo:: syntax papercut. Gets everyone, sorry. It's the price of using for type parameters rather than []. We need a better error message for it. Actually, [] would have the same problem, because of array indexing. Naturally, which is why array indexing (way back when) was foo.(index). But it was a throwaway comment; this is all very much water under the bridge, not in any way suggesting we revisit. -Graydon ___ 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] Dynamic in Rust
And here is another implementation of the same interface, implemented in a much more brute force way. It is probably more efficient that the above, and also about 5% as elegant. mod UnsafeUniversal { use std::managed; use std::cast; // We use pointers as our tags, since they are easy to generate // uniquely and compare for equality. Uniquely generated integers // might be better, but this is really simple and kind of cute. type InnerTag = @(); fn new_inner_tag() - InnerTag { @() } fn tag_eq(x: InnerTag, y: InnerTag) - bool { managed::ptr_eq(x, y) } pub struct Univ { tag: InnerTag, value: @() } pub struct TagA { priv inner: InnerTag } pub fn new_tagA:'static() - TagA { Tag { inner: new_inner_tag() } } pub fn injectA:Clone+'static(tag: TagA, x: A) - Univ { Univ { tag: tag.inner, value: unsafe { cast::transmute(@(x.clone())) } } } pub fn projectA:Clone+'static(tag: TagA, x: Univ) - OptionA { if tag_eq(tag.inner, x.tag) { let ptr: @A = unsafe { cast::transmute(x.value) }; Some((*ptr).clone()) } else { None } } } On Fri, Aug 23, 2013 at 4:54 PM, Michael Sullivan su...@msully.net wrote: So, as it turns out, something closely related can be implemented in completely safe rust. (The ideas here are based on http://mlton.org/UniversalType and the presentation of extensible types from my undergrad PL class. The implementation is based on the mlton UniversalType page, but I change the interface to be more like extensible types. If anybody cares, SML code for this is https://gist.github.com/msullivan/6324908.) We can implement a universal type that values of any (cloneable, not containing borrowed pointers) type can be injected to. The catch is that the values aren't actually keyed by the type, but by tags that are generated at runtime. This is sometimes useful (you can distinguish between different classes of values of the same type) and sometimes annoying (you have to manage the tags). The implementation here is pretty clever, but also kind of silly. It would probably actually be better in practice to do something unsafe internally with dynamically generated tag values. mod ClosureUniversal { // A value of universal type is a pair of functions. store will // write the underlying value into the associated tag, while clear // will erase the data in the tag to prevent space leaks. pub struct Univ { priv store: @fn(), priv clear: @fn() } // A tag is a mutable option used as a scratch space to write // into when inspecting a tag. pub struct TagA { priv r: @mut OptionA } pub fn new_tagA:'static() - TagA { Tag { r: @mut None } } pub fn injectA:Clone+'static(tag: TagA, x: A) - Univ { Univ { store: || *tag.r = Some(x.clone()), clear: || *tag.r = None } } pub fn projectA:Clone+'static(tag: TagA, x: Univ) - OptionA { // Cause the value to be written into its tag. If the universal // value was injected with our tag, then it will be in tag.r. (x.store)(); // Read out the value. let res = (*tag.r).clone(); // Clear the value, to prevent space leaks. (x.clear)(); res } } fn main() { use ClosureUniversal::*; // Create some tags let int_tag = new_tag::int(); let str_tag = new_tag::~str(); // Create some universal values with those tags let u1 = inject(int_tag, 5); let u2 = inject(int_tag, 6); let u3 = inject(str_tag, ~hello, world); // Try reading them println(fmt!(%?, project(int_tag, u1))); // Some(5) println(fmt!(%?, project(int_tag, u2))); // Some(6) println(fmt!(%?, project(int_tag, u3))); // None println(fmt!(%?, project(str_tag, u1))); // None println(fmt!(%?, project(str_tag, u2))); // None println(fmt!(%?, project(str_tag, u3))); // Some(~hello, world) // Try out a *different* int tag. let int_tag2 = new_tag::int(); // It can not be used to read things created by the other int tag println(fmt!(%?, project(int_tag2, u1))); // None } (Code is also up at https://gist.github.com/msullivan/6324973) On Fri, Aug 23, 2013 at 11:22 AM, Graydon Hoare gray...@mozilla.comwrote: On 13-08-23 11:16 AM, Patrick Walton wrote: On 8/23/13 11:15 AM, Graydon Hoare wrote: get_tydesc::T(). This is the foo vs foo:: syntax papercut. Gets everyone, sorry. It's the price of using for type parameters rather than []. We need a better error message for it. Actually, [] would have the same problem, because of array indexing. Naturally, which is why array indexing (way back when) was foo.(index). But it was a throwaway comment; this is all very much water
Re: [rust-dev] Dynamic in Rust
On Thu, Aug 22, 2013 at 9:49 PM, Oren Ben-Kiki o...@ben-kiki.org wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? I'm sure you've all seen it, but C# has something similar but a lot more powerful. Basically, it has support for allowing runtime resolution of types if they are declared as having the dynamic type. But it's even better, the specification for how that resolution happens is defined in a library. This way you can work directly with dynamic values without having to cast them first (e.g. imagine just dotting your way through a JSON document and parse it on-demand). See For how it's used: http://msdn.microsoft.com/en-us/library/vstudio/dd264736.aspx For how to implement dynamic libraries (e.g. decide what happens when a field is accessed, or a method is called, on your dynamic objects): http://msdn.microsoft.com/en-us/library/vstudio/system.dynamic.dynamicobject.aspx -- Sebastian Sylvan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
[rust-dev] Dynamic in Rust
Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Dynamic in Rust
You could define an enum that encapsulates all known types. enum monster { Integer(int), Float(float), } Then use a container for this type. On Aug 23, 2013 10:20 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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] Dynamic in Rust
That would require me to declare up front which types were usable and which weren't. I'm looking for a solution where I don't need to do that; that is, allow me to add new components to the system with new configuration parameter types, without having to go to a central source location and declare these types there. On Fri, Aug 23, 2013 at 7:54 AM, Abhijeet Gaiha abhijeet.ga...@gmail.comwrote: You could define an enum that encapsulates all known types. enum monster { Integer(int), Float(float), } Then use a container for this type. On Aug 23, 2013 10:20 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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] Dynamic in Rust
I think your second solution is what will work. You can use unsafe code and a void pointer combined with a type descriptor string. I would probably combine the void pointer and string in a struct. On Aug 23, 2013 10:27 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: That would require me to declare up front which types were usable and which weren't. I'm looking for a solution where I don't need to do that; that is, allow me to add new components to the system with new configuration parameter types, without having to go to a central source location and declare these types there. On Fri, Aug 23, 2013 at 7:54 AM, Abhijeet Gaiha abhijeet.ga...@gmail.comwrote: You could define an enum that encapsulates all known types. enum monster { Integer(int), Float(float), } Then use a container for this type. On Aug 23, 2013 10:20 AM, Oren Ben-Kiki o...@ben-kiki.org wrote: Is it possible to implement something like Haskell's Dynamic value holder in Rust? (This would be similar to supporting C++'s dynamic_cast). Basically, something like this: pub struct Dynamic { ... } impl Dynamic { pub fn put(value: ~T) { ... } pub fn get() - OptionT { ... } } I guess this would require unsafe code... even so, it seems to me that Rust pointers don't carry sufficient meta-data for the above to work. A possible workaround would be something like: pub struct Dynamic { type_name: ~str, ... } impl Dynamic { pub fn put(type_name: str, value: ~T) { Dynamic { type_name: type_name, ... } } pub fn get('a self, type_name: str) - Option'a T { assert_eq!(type_name, self.type_name); ... } } } And placing the burden on the caller to always use the type name int when putting or getting `int` values, etc. This would still require some sort of unsafe code to cast the `~T` pointer into something and back, while ensuring that the storage for the `T` (whatever its size is) is not released until the `Dynamic` itself is. (Why do I need such a monstrosity? Well, I need it to define a `Configuration` container, which holds key/value pairs where whoever sets a value knows its type, whoever gets the value should ask for the same type, and the configuration can hold values of any type - not from a predefined list of types). Is such a thing possible, and if so, how? Thanks, Oren Ben-Kiki ___ 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