Can the following C# code be translated to Rust?
dynamic x = 109;
x = "Hi";
I'm asking for a general dynamic type to allow creating an array of dynamic values. For example:
var l = new dynamic[2];
l[0] = 102;
l[1] = "Hi";
One option is to use a vector of Any (link to beta because the stable docs is not showing the methods defined for Any, but they are stable):
use std::any::Any;
fn main() {
let mut v: Vec<Box<Any>> = vec![];
v.push(Box::new(102usize));
v.push(Box::new("Hi"));
for item in &v {
// to do an operation, it is necessary to downcast to
// a concrete type
if let Some(x) = item.downcast_ref::<usize>() {
println!("num = {:?}", x)
}
}
}
Note that, contrary to dynamic in C#, that is assumed to support any operation, a value of type Any (Box<Any>) only support the operations defined in Any (Box<Any> and Any). A downcast is necessary to call any method of the concrete type.
I think that it is not possible to have a type like dynamic of C# in Rust. To support calling any method on a dynamic value, it is necessary to have (complete) runtime reflection support, and Rust does not provide it.
If you know the methods that will be called, then the best option is to define a trait and use Box<Trait> (Any is not necessary in this case).
Not directly. You can just create a new binding for x:
fn main() {
let x = 109;
let x = "Hi";
}
Depending on your use case, you might be able to use a generic bounded by a trait or a trait object to achieve similar goals:
use std::fmt::Display;
fn main() {
let mut x: Box<Display> = Box::new(109);
x = Box::new("Hi");
}
However, the C# docs state:
At compile time, an element that is typed as dynamic is assumed to support any operation.
This is not true for a trait object; a trait object only can be used for the explicit methods in the trait. I have not found this to be a significant hurdle in the code I have written. Generally, there's a fixed number of methods that I want to call so it's possible to map those to a trait. In other cases, I can provide a generic type to allow the user to specify a type that fits their case.
Related
I want to use multiple libraries that each have their own error types. I don't really care about each specific crate's error type and I want to use the ? idiom to use the methods of those crates that return a Result type.
I don't want to unwrap the values either, that would cause a panic if it hits an error. I might just want to propagate the different errors using ? to the top and perhaps choose to deal with them or ignore them if I want.
I cannot do that with a std::result::Result<T, E> because I don't know the type of error returned (like I said, each crate could return its own errors).
I am aware that in Rust there is no "object-oriented" polymorphism, but there are trait objects. Since a trait object's size cannot be known at compile time, we must hide them behind some kind of pointer like & or Box<_>.
The base trait implemented by errors seems to be std::error::Error.
One thing I've seen is the fn foo() -> Result<Blah, Box<dyn Error>> strategy, which utilizes the concept of trait objects.
The problem with this strategy is none of the crates return a boxed error, which leads to the compiler complaining about the same.
An example use-case:
use native_tls::TlsConnector; // 0.2.3
use std::io::{Read, Write};
use std::net::TcpStream;
fn main() {
match do_stuff() {
Ok(string) => {
println!("{}", string);
}
_ => {
println!("Failed!");
}
}
}
fn do_stuff() -> Result<String, Box<(dyn std::error::Error + 'static)>> {
let connector = TlsConnector::new()?;
let stream = TcpStream::connect("jsonplaceholder.typicode.com:443")?;
let mut stream = connector.connect("jsonplaceholder.typicode.com", stream)?;
stream.write_all(b"GET /todos/1 HTTP/1.0\r\n\r\n")?;
let mut res = vec![];
stream.read_to_end(&mut res)?;
String::from_utf8(res)
}
playground
Is there an easy way around this problem? Can I easily abstract away all the different errors and return a Result so I can use the ? idiom?
Can you return a Result that works with any possible error type?
No, you cannot. On the surface, this cannot make sense. Generic types are chosen by the caller of the function, so how would a function create an error that was chosen by someone else, without being told how to construct it?
That said, your problem is easily solved. You said:
so I can use the ? idiom
If you do that consistently, your program compiles:
let s = String::from_utf8(res)?;
Ok(s)
You could also convert the error type directly:
String::from_utf8(res).map_err(Into::into)
none of the crates return a boxed error, which leads to the compiler complaining about the same
It does not for the 5 other cases where you've used ?, so it's unclear why you make this statement.
Specifically, Box<dyn Error> can be created from any type that implements Error:
impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
fn from(err: E) -> Box<dyn Error + 'a> {
Box::new(err)
}
}
The ? operator calls From::from for you under the hood.
See also:
What is this question mark operator about?
How to manually return a Result<(), Box<dyn Error>>?
Rust proper error handling (auto convert from one error type to another with question mark)
This question already has answers here:
How to get a reference to a concrete type from a trait object?
(2 answers)
Closed 4 years ago.
I have a collection of interfaces that are loaded dynamically from shared libraries. I want to be able to convert those downcasted interfaces to their original type (trait).
struct A {}
fn abstract_a<'l>() -> &'l Any { return &A{} }
trait TargetTrait { fn some_method(); }
impl TargetTrait for A { fn some_method() { println!("HELLO"); } }
fn main() {
let x: &Any = abstract_a();
let y: &TargetTrait = magic_conversion<&TargetTrait> (x);
}
// question: does 'magic_conversion'(or 'dynamic_cast') exist? what is it?
While loading these is not a problem, I have no idea how to get target functionality with such interface. In other words:
/* simplified for readability */
// this part is known
let some_lib = loadlib("path/to/lib.so")
let some_interface: &Any = some_lib.loadfunc<&Any>("constructor_func")()
/* loader does not know what target type constructor has, so it presumes 'Any' */
// the problem:
let dependent_class = Some(class)
dependent_class.graphics = dynamic_cast<IGraphics>(some_interface)
In this example, dependent_class uses an extern interface and does not care about handling libloading and all of that complicated stuff.
If there is another way to achieve my goal, I would also be very happy to see it, but the only solution I came up with is 'dynamic_cast'
I think what you're looking for is downcast_ref::<A>:
let y: &TargetTrait = Any::downcast_ref::<A>(x).expect("Expected an A");
You have to specify the concrete type A. Any trait objects don't hold any information about what traits the underlying type implements, so you can't "cross-cast" from &Any to &TargetTrait directly; you have to know the underlying type.
The expect will panic if downcast_ref returns None; if that's not what you want, you have to decide what you want to happen when x is not an A and match against the result of downcast_ref instead.
I encountered an unfamiliar pattern of initialization from Objective-C that I'm struggling to replicate in Swift.
Objective-C
In the example code, they defined a C struct such as this (abbreviated, original here):
struct AQPlayerState {
AudioFileID mAudioFile;
}
Here's an example that uses AQPlayerState:
AQPlayerState aqData; // 1
OSStattus result =
AudioFileOpenURL(
audioFileURL,
fsRdPerm,
0,
&aqData.mAudioFile // 2
);
The key takeaway from above is that aqData currently has uninitialized properties, and AudioFileOpenURL is initializing aqData.mAudioFile on it's behalf.
Swift
I'm trying to replicate this behaviour in Swift. Here's what I've tried so far:
Models:
class Person {
var name: String
init(name: String) {
self.name = name
}
}
class Foo {
var person: Person?
}
My idea was to replicate the Objective-C code by passing a reference of Foo.person into a function that would instantiate it on it's behalf.
Initialization Function:
func initializeWithBob(_ ptr: UnsafeMutablePointer<Person?>) {
ptr.pointee = Person(name: "Bob")
}
initializeWithBob takes a pointer to an address for a Person? type and initializes it with a Person(name: "Bob") object.
Here's my test code:
let foo = Foo()
let ptr = UnsafeMutablePointer<Person?>.allocate(capacity: 1)
ptr.initialize(to: foo.person)
defer {
ptr.deinitialize()
ptr.deallocate(capacity: 1)
}
initializeWithBob(ptr)
print(foo.person) // outputs nil
initializeWithBob failed to "install" an instance of type Person in my Foo instance. I presume some of my assumptions are wrong. Looking for help in correcting my assumptions and understanding of this situation.
Thanks in advance!
You can achieve what you are looking for via withUnsafeMutablePointer(to:_:) like so:
let foo = Foo()
withUnsafeMutablePointer(to: &foo.person) { (ptr) -> Void in
initializeWithBob(ptr)
}
print(foo.person!.name) // outputs Bob
However, I wouldn't recommend this approach. IMHO it makes more sense to wrap the APIs you are working with in a C function that you can make 'nice' to call from Swift. The problem with your current approach is that this type of Swift is hard to read for Swift developers and also hard to read for Audio Toolbox developers.
#kelvinlau Is this what you were thinking of trying to achieve?
func initializeWithBob(_ ptr: UnsafeMutablePointer<Foo>) {
ptr.pointee.person = Person(name: "Bob")
}
let foo = Foo()
let ptr = UnsafeMutablePointer<Foo>.allocate(capacity: 1)
ptr.initialize(to: foo)
initializeWithBob(ptr)
print(foo.person?.name ?? "nil")
ptr.deinitialize()
ptr.deallocate(capacity: 1)
print(foo.person?.name ?? "nil")
The code pattern you have in Objective-C is for out parameters, that is parameters which return a value, or in out parameters, that is parameters which both pass a value in and return one. Objective-C does not directly support these so pointers are used to produce the semantics.
Swift has in out parameters indicated by the keyword inout in the function declaration. Within the function an assignment to an inout parameters effectively assigns a value to the variable that was passed as the argument. At the function call site the variable must be prefixed by & to indicate it is the variable itself and not its value which is effectively being passed.
Keeping your Person and Foo as is your function becomes:
func initializeWithBob(_ ptr: inout Person?)
{
ptr = Person(name: "Bob")
}
and it may be used, for example, like:
var example = Foo()
initializeWithBob(&example.person)
Using inout in Swift is better than trying to build the same semantics using pointers.
HTH
Note: You can skip this unless you are curious
"Effectively" was used a few times above. Typically out parameters are implemented by the parameter passing method call-by-result, while in out use call-by-value-result. Using either of these methods the returned value is only assigned to the passed variable at the point the function returns.
Another parameter passing method is call-by-reference, which is similar to call-by-value-result except that each and every assignment to the parameter within the function is immediately made to passed variable. This means changes to the passed variable may be visible before the function returns.
Swift by design does not specify whether its inout uses call-by-value-result or call-by-reference. So rather than specify the exact semantics in the answer "effectively" is used.
I'm trying to implement an iterator on my own struct. My general approach is by generating and storing an iterator the first time next is invoked, and then calling this iterator each time I need a value.
My minimal failing example looks like this, and the heart of it is:
if !self.vals.is_some() {
self.vals = Some(Box::new({
self.display.chars().filter(|&i| i == self.look_for)
}) as Box<std::iter::Iterator<Item = _>>);
}
My code fails to compile, producing the following message:
help: consider using an explicit lifetime parameter as shown: fn next(self: &'a mut Self) -> Option<<Self>::Item>
Following the advice doesn't help (just leads to more compile errors saying that my implementation is incompatible with the Iterator trait definition.
I'd appreciate help understanding what's going wrong and how I can fix it.
The problem is that the closure you pass to filter needs to borrow self, but you can't store a reference to self in the struct itself.
In this case, we can work around it by storing a copy of the value in the closure instead. This is done in two steps:
Assign self.look_for to a local variable, and use the local variable in the closure instead. This way, the closure is not tied to self.
Add move to the closure. The closure will thus capture the local variable by value.
Here's the final code:
impl<'a> Iterator for StatefulCounter<'a> {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if !self.vals.is_some() {
let look_for = self.look_for;
self.vals = Some(Box::new({
self.display.chars().filter(move |&i| i == look_for)
}));
}
if let &Some(v) = &self.vals.as_mut().unwrap().next() {
Some(expensive(v))
} else {
None
}
}
}
The explicit cast on the Box is not necessary, so I removed it.
Returning an iterator from a function in Rust is an exercise of Sisyphean dimensions, but I am told it's possible to return one as a trait without quite so much pain. Unfortunately, it isn't working: apparently, I need an explicit lifetime bound? Which is apparently not the same thing as adding a lifetime parameter. Which means I have no idea how to do that.
Here's my (tiny, test) code:
fn main() {
let args = get_args();
for arg in args {
println!("{}", arg);
}
}
fn get_args() -> Iterator {
std::env::args().filter_map(|arg| arg.into_string().ok())
}
What is the appropriate way to make this actually work?
Edit: rust version rustc 1.0.0-nightly (00df3251f 2015-02-08 23:24:33 +0000)
You can't return a bare Iterator from a function, because it is a trait, thus not a sized type.
In your situation, you'll need to put the iterator object inside a box, in order to make it into a sized object that can be returned from the function.
To do so, you can change your code like this:
fn get_args() -> Box<Iterator<Item=String> + 'static> {
Box::new(std::env::args().filter_map(|arg| arg.into_string().ok()))
}
Here I've added a lifetime specifier 'static for the trait object, meaning that it is completely self-owned (a function taking no arguments will almost always return something valid for the 'static lifetime in this sense).
You also need the <Item=String> part to explicit the type of data yielded by your iterator. In this case: Strings.
In this specific case you can manage to return a concrete type from your get_args, like so:
fn get_args() -> FilterMap<Args, fn(OsString) -> Option<String>> {
fn arg_into_string(arg: OsString) -> Option<String> { arg.into_string().ok() }
args().filter_map(arg_into_string as fn(OsString) -> Option<String>)
}
basically this applies to all the cases where the closure you use in the iterator adapter (in your case filter_map) is not really a closure, in that it does not capture any environment, and it can be modeled by a plain old function.
In general, if you do need to return a type that does contain a closure, you will indeed need to box it and return a trait object. In your case:
fn get_args() -> Box<Iterator<Item=String> + 'static> {
Box::new(std::env::args().filter_map(|arg| arg.into_string().ok()))
}