Declaring a map in a separate file and reading its contents - rust

I'm trying to declare a map in a separate file, and then access it from my main function.
I want Rust's equivalent (or whatever comes closest) to this C++ map:
static const std::map<std::string, std::vector<std::string>> table = {
{ "a", { "foo" } },
{ "e", { "bar", "baz" } }
};
This is my attempt in Rust.
table.rs
use std::container::Map;
pub static table: &'static Map<~str, ~[~str]> = (~[
(~"a", ~[~"foo"]),
(~"e", ~[~"bar", ~"baz"])
]).move_iter().collect();
main.rs
mod table;
fn main() {
println(fmt!("%?", table::table));
}
The above gives two compiler errors in table.rs, saying "constant contains unimplemented expression type".
I also have the feeling that the map declaration is less than optimal for the purpose.
Finally, I'm using Rust 0.8.

As Chris Morgan noted, rust doesn't allow you to run user code in order to initialize global variables before main is entered, unlike C++. So you are mostly limited to primitive types that you can initialize with literal expressions. This is, afaik, part of the design and unlikely to change, even though the particular error message is probably not final.
Depending on your use case, you might want to change your code so you're manually passing your map as an argument to all the functions that will want to use it (ugh!), use task-local storage to initialize a tls slot with your map early on and then refer to it later in the same task (ugh?), or use unsafe code and a static mut variable to do much the same with your map wrapped in an Option maybe so it can start its life as None (ugh!).

Related

Moving context into several closures?

I have found a way to move context into several closures, but it looks ugly. I do it with help of Rc and cloning each variable I need to use for each closure. Particularly I don't like to clone every variable for every closure I want to use:
let mut context = Rc::new( Context { a : 13 } );
..
let context_clone_1 = Rc::clone( &context );
engine.on_event1( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
let context_clone_2 = Rc::clone( &context );
engine.on_event2( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
It is an extensive way to go and I feel there must be a better way to do it. Also, uncommenting line // context_clone_1.a += 1; breaks the compilation. What is the proper way of solving problems like this in Rust?
Here is a playground with minimal code.
There are two "problems" here:
Since you specifically asked about context_clone_1.a += 1;: When putting a value into an Rc, there could be multiple references to that value, derived from the independent Rc owners. If mutation was allowed, this would also allow simultaneous mutation and aliasing, which is not allowed in Rust; therefore Rc does not allow mutating its inner value. A common approach to regain mutability is to put the value into a RefCell, which provides mutability through try_borrow_mut() with a runtime check that ensures no aliasing occurs. A Rc<RefCell<T>> is commonly seen in Rust.
Regarding the use of Rc: The way your code is currently set up is actually fine, at least if that's how it should work. The way the code is currently structured allows for flexibility, including cases where multiple Context-objects provide callback implementations on different events. For example, this is currently possible:
let context1 = Context { a : 13 };
engine.on_event1(Box::new(move ||
{
println!("on_event1 : {}", context1.a );
});
let context2 = Context { a : 999 };
engine.on_event2(Box::new(move ||
{
println!("on_event1 : {}", context2.a );
});
In case you have exactly one Context (as in your example), and since the Engine needs to make sure that all callbacks are alive while it itself is alive, you'll need to put each callback - which is structured as a completely separate thing - into a Rc. In your case, all Rc end up pointing to the same object; but they don't have to and this is what your code currently allows for.
A more simple solution would be to define a trait for Context, something along the lines of
trait EventDriver {
fn event1(&mut self, &Engine);
fn event2(&mut self, &Engine);
}
... and then have Context implement the trait. The Engine-struct then becomes generic over E: EventDriver and Context becomes the E in that. This solution only allows for exactly one instance of Context to provide event callbacks. But since Engine is the owner of that object, it can be sure that all callbacks are alive while it itself is alive and the whole Rc-thing goes away.

How can I make this Rust code more idiomatic

Recently I started to learn Rust and one of my main struggles is converting years of Object Oriented thinking into procedural code.
I'm trying to parse a XML that have tags that are processed by an specific handler that can deal with the data it gets from the children.
Further more I have some field members that are common between them and I would prefer not to have to write the same fields to all the handlers.
I tried my hand on it and my code came out like this:
use roxmltree::Node; // roxmltree = "0.14.0"
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
let tag_handler: dyn XMLTagHandler = match tag_name {
"name" => NameHandler::new(),
"phone" => PhoneHandler::new(),
_ => DefaultHandler::new()
}
if tag_handler.is_recursive() {
for child in node.children() {
let child_value = get_data_from(&child);
// do something with child value
}
}
let value: String = tag_handler.value()
value
}
// consider that handlers are on my project and can be adapted to my needs, and that XMLTagHandler is the trait that they share in common.
My main issues with this are:
This feels like a Object oriented approach to it;
is_recursive needs to be reimplemented to each struct because they traits cannot have field members, and I will have to add more fields later, which means more boilerplate for each new field;
I could use one type for a Handler and pass to it a function pointer, but this approach seems dirty. e.g.:=> Handler::new(my_other_params, phone_handler_func)
This feels like a Object oriented approach to it
Actually, I don't think so. This code is in clear violation of the Tell-Don't-Ask principle, which falls out from the central idea of object-oriented programming: the encapsulation of data and related behavior into objects. The objects (NameHandler, PhoneHandler, etc.) don't have enough knowledge about what they are to do things on their own, so get_data_from has to query them for information and decide what to do, rather than simply sending a message and letting the object figure out how to deal with it.
So let's start by moving the knowledge about what to do with each kind of tag into the handler itself:
trait XmlTagHandler {
fn foreach_child<F: FnMut(&Node)>(&self, node: &Node, callback: F);
}
impl XmlTagHandler for NameHandler {
fn foreach_child<F: FnMut(&Node)>(&self, _node: &Node, _callback: F) {
// "name" is not a recursive tag, so do nothing
}
}
impl XmlTagHandler for DefaultHandler {
fn foreach_child<F: FnMut(&Node)>(&self, node: &Node, callback: F) {
// all other tags may be recursive
for child in node.children() {
callback(child);
}
}
}
This way you call foreach_child on every kind of Handler, and let the handler itself decide whether the right action is to recurse or not. After all, that's why they have different types -- right?
To get rid of the dyn part, which is unnecessary, let's write a little generic helper function that uses XmlTagHandler to handle one specific kind of tag, and modify get_data_from so it just dispatches to the correct parameterized version of it. (I'll suppose that XmlTagHandler also has a new function so that you can create one generically.)
fn handle_tag<H: XmlTagHandler>(node: &Node) -> String {
let handler = H::new();
handler.foreach_child(node, |child| {
// do something with child value
});
handler.value()
}
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
match tag_name {
"name" => handle_tag::<NameHandler>(node),
"phone" => handle_tag::<PhoneHandler>(node),
_ => handle_tag::<DefaultHandler>(node),
}
}
If you don't like handle_tag::<SomeHandler>(node), also consider making handle_tag a provided method of XmlTagHandler, so you can instead write SomeHandler::handle(node).
Note that I have not really changed any of the data structures. Your presumption of an XmlTagHandler trait and various Handler implementors is a pretty normal way to organize code. However, in this case, it doesn't offer any real improvement over just writing three separate functions:
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
match tag_name {
"name" => get_name_from(node),
"phone" => get_phone_from(node),
_ => get_other_from(node),
}
}
In some languages, such as Java, all code has to be part of some class – so you can find yourself writing classes that don't exist for any other reason than to group related things together. In Rust you don't need to do this, so make sure that any added complication such as XmlTagHandler is actually pulling its weight.
is_recursive needs to be reimplemented to each struct because they traits cannot have field members, and I will have to add more fields later, which means more boilerplate for each new field
Without more information about the fields, it's impossible to really understand what problem you're facing here; however, in general, if there is a family of structs that have some data in common, you may want to make a generic struct instead of a trait. See the answers to How to reuse codes for Binary Search Tree, Red-Black Tree, and AVL Tree? for more suggestions.
I could use one type for a Handler and pass to it a function pointer, but this approach seems dirty
Elegance is sometimes a useful thing, but it is subjective. I would recommend closures rather than function pointers, but this suggestion doesn't seem "dirty" to me. Making closures and putting them in data structures is a very normal way to write Rust code. If you can elaborate on what you don't like about it, perhaps someone could point out ways to improve it.

Can't use a neon JsArray: This function takes 3 parameters but 2 were supplied

I'm learning how to use neon, but I don't understand a thing. If I try to execute this code:
#[macro_use]
extern crate neon;
use neon::vm::{Call, JsResult};
use neon::mem::Handle;
use neon::js::{JsInteger, JsNumber, JsString, JsObject, JsArray, JsValue, Object, Key};
use neon::js::error::{JsError, Kind};
fn test(call: Call) -> JsResult<JsArray> {
let scope = call.scope;
let js_arr: Handle<JsArray> = try!(try!(call.arguments.require(scope, 1)).check::<JsArray>());
js_arr.set(0, JsNumber::new(scope, 1000));
Ok(js_arr)
}
register_module!(m, {
m.export("test", test)
});
I get this error when I call js_arr.set: This function takes 3 parameters but 2 were supplied.
I don't understand why since it's a JsArray. Even Racer tells me that the set method takes 2 parameters. No matter what, js_arr.set takes 3 parameters in this order: &mut bool, neon::macro_internal::runtime::raw::Local and neon::macro_internal::runtime::raw::Local.
What's happening? I can't understand how JsArray works.
As paulsevere says on a GitHub issue for Neon, import neon::js::Object. In addition, do not import Key, which also provides a set method:
#[macro_use]
extern crate neon;
use neon::vm::{Call, JsResult};
use neon::js::{Object, JsArray, JsInteger, JsObject, JsNumber};
fn make_an_array(call: Call) -> JsResult<JsArray> {
let scope = call.scope; // the current scope for rooting handles
let array = JsArray::new(scope, 3);
array.set(0, JsInteger::new(scope, 9000))?;
array.set(1, JsObject::new(scope))?;
array.set(2, JsNumber::new(scope, 3.14159))?;
Ok(array)
}
register_module!(m, {
m.export("main", make_an_array)
});
This creates a brand new array. If you'd like to accept an array as the first argument to your function and then modify it, this works:
#[macro_use]
extern crate neon;
use neon::vm::{Call, JsResult};
use neon::js::{Object, JsArray, JsInteger, JsUndefined};
use neon::mem::Handle;
fn hello(call: Call) -> JsResult<JsUndefined> {
let scope = call.scope;
let js_arr: Handle<JsArray> = call.arguments.require(scope, 0)?.check::<JsArray>()?;
js_arr.set(0, JsInteger::new(scope, 1000))?;
Ok(JsUndefined::new())
}
register_module!(m, {
m.export("hello", hello)
});
let js_arr: Handle<JsArray> makes it clear that js_arr is a Handle<JsArray> and Handle<T> has this method:
unsafe fn set(self, out: &mut bool, obj: Local, val: Local) -> bool
I'd guess that you're accidentally trying to call Handle::set (which is unsafe and takes three non-self arguments) rather than JsArray::set (which is safe and takes two non-self arguments).
If that's the case, you need to force a deref_mut to occur. (_mut because JsArray::set takes &mut self.)
I haven't run into this sort of naming collision before, so I can't be certain whether the auto-deref is smart enough, but something like this may work:
(&mut js_arr).set(0, JsNumber::new(scope, 1000));
Failing that, two other things to try are:
JsArray::set(&mut js_arr, 0, JsNumber::new(scope, 1000));
(If the former example fails because it's too much like C++-style method overloading. This is known as Fully Qualified Syntax and is normally used to disambiguate when an object implements two traits which provide methods of the same name.)
Call js_arr.deref_mut() directly to get a mutable reference to the underlying JsArray, then call set on that.

Struct declaration order

If I define structs at the module level, I can reference not-yet defined structs.
struct S {
ComesLater c;
}
struct ComesLater {}
But If I do the same inside an unittest or a function block, it doesn't work:
unittest {
struct S {
ComesLater c;
}
struct ComesLater {}
}
Error: undefined identifier 'ComesLater'
Why is that? How can I get order-independent declarations inside functions? Is there some kind of forward-declaration in d? I need this because I generate structs using mixin and ordering the declarations in the order of their inner-dependencies would be quite some effort, sometimes impossible, if there are circularly referencing structs. (using pointers.)
Declarations inside functions, unittests, or anywhere else that statements can actually be executed are indeed order-dependent because their values may depend on the code before them running. Think of a local variable:
int a;
writeln(a);
a = b;
int b = get_user_line();
If order wasn't important there, when would the two functions get called? Would the user be asked for a line before the writeln as the declarations are rewritten?
The current behavior of making b an undefined variable error keeps it simple and straightforward.
It works independent of order in other contexts because there is no executable code that it can depend on, so there's no behavior that can change if the compiler needs to internally think about it differently.
So:
How can I get order-independent declarations inside functions?
Change the context such that there is no executable code... put it all inside another struct!
void main() { // or unittest { }
struct Holder {
static struct S {
C c;
}
static struct C {}
}
}
Since execution happens around the holder and doesn't happen inside it, the order of declaration inside doesn't matter again. Since you can define almost anything inside a struct, you can use this for variables, functions, other structs, and so on. Basically all you have to do is wrap your existing code inside the struct Holder {} brackets.
By making everything static inside, you can just use it like a container and reference the stuff with Holder.S, etc., on the outside.

dart method calling context

I used the below to see how dart calls methods passed in to other methods to see what context the passed in method would/can be called under.
void main() {
var one = new IDable(1);
var two = new IDable(2);
print('one ${caller(one.getMyId)}'); //one 1
print('two ${caller(two.getMyId)}'); //two 2
print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception
}
class IDable{
int id;
IDable(this.id);
int getMyId(){
return id;
}
}
caller(fn){
return fn();
}
callerJustForThree(fn){
var three = new IDable(3);
three.fn();
}
So how does caller manager to call its argument fn without a context i.e. one.fn(), and why does callerJustForThree fail to call a passed in fn on an object which has that function defined for it?
In Dart there is a difference between an instance-method, declared as part of a class, and other functions (like closures and static functions).
Instance methods are the only ones (except for constructors) that can access this. Conceptually they are part of the class description and not the object. That is, when you do a method call o.foo() Dart first extracts the class-type of o. Then it searches for foo in the class description (recursively going through the super classes, if necessary). Finally it applies the found method with this set to o.
In addition to being able to invoke methods on objects (o.foo()) it is also possible to get a bound closure: o.foo (without the parenthesis for the invocation). However, and this is crucial, this form is just syntactic sugar for (<args>) => o.foo(<args>). That is, this just creates a fresh closure that captures o and redirects calls to it to the instance method.
This whole setup has several important consequences:
You can tear off instance methods and get a bound closure. The result of o.foo is automatically bound to o. No need to bind it yourself (but also no way to bind it to a different instance). This is way, in your example, one.getMyId works. You are actually getting the following closure: () => one.getMyId() instead.
It is not possible to add or remove methods to objects. You would need to change the class description and this is something that is (intentionally) not supported.
var f = o.foo; implies that you get a fresh closure all the time. This means that you cannot use this bound closure as a key in a hashtable. For example, register(o.foo) followed by unregister(o.foo) will most likely not work, because each o.foo will be different. You can easily see this by trying print(o.foo == o.foo).
You cannot transfer methods from one object to another. However you try to access instance methods, they will always be bound.
Looking at your examples:
print('one ${caller(one.getMyId)}'); //one 1
print('two ${caller(two.getMyId)}'); //two 2
print('one ${callerJustForThree(one.getMyId)}'); //NoSuchMethod Exception
These lines are equivalent to:
print('one ${caller(() => one.getMyId())}');
print('two ${caller(() => two.getMyId())}');
print('one ${callerJustForThree(() => one.getMyId())}';
Inside callerJustForThree:
callerJustForThree(fn){
var three = new IDable(3);
three.fn();
}
The given argument fn is completely ignored. When doing three.fn() in the last line Dart will find the class description of three (which is IDable) and then search for fn in it. Since it doesn't find one it will call the noSuchMethod fallback. The fn argument is ignored.
If you want to call an instance member depending on some argument you could rewrite the last example as follows:
main() {
...
callerJustForThree((o) => o.getMyId());
}
callerJustForThree(invokeIDableMember){
var three = new IDable(3);
invokeIDableMember(three);
}
I'll try to explain, which is not necessarily a strength of mine. If something I wrote isn't understandable, feel free to give me a shout.
Think of methods as normal objects, like every other variable, too.
When you call caller(one.getMyId), you aren't really passing a reference to the method of the class definition - you pass the method "object" specific for instance one.
In callerJustForThree, you pass the same method "object" of instance one. But you don't call it. Instead of calling the object fn in the scope if your method, you are calling the object fn of the instance three, which doesn't exist, because you didn't define it in the class.
Consider this code, using normal variables:
void main() {
var one = new IDable(1);
var two = new IDable(2);
caller(one.id);
caller(two.id);
callerJustForThree(one.id);
}
class IDable{
int id;
IDable(this.id);
}
caller(param){
print(param);
}
callerJustForThree(param){
var three = new IDable(3);
print(three.id); // This works
print(param); // This works, too
print(three.param); // But why should this work?
}
It's exactly the same concept. Think of your callbacks as normal variables, and everything makes sense. At least I hope so, if I explained it good enough.

Resources