Get reference to an element of a global vector - static

This is a minimal example that I struggled to get right.
I am trying to maintain a global Vec<Box<Item>>, the id of the Item is its index. When I want to fetch a reference to the Item, I can always get its id from somewhere, then get a reference by id (as ref_a in the code). But I would prefer directly getting the reference to the Item and pass it around (like ref_b), or even save it somewhere instead of saving the id. But my code doesn't work.
I see that in get_a_certain_item(), the return value &Item would have the same lifetime as VEC.read() thus it is not valid to let the reference escape. However, in my understanding, since all the Items are allocated with boxes in the heap, a reference to it should always be valid. There should be no harm to let the reference live longer than the read guard.
If I am not writing the code right, I guess there should be some idiomatic way to do this in Rust. I would appreciate some help.
// lazy_static = "0.1.15"
#[macro_use]
extern crate lazy_static;
use std::sync::RwLock;
struct Item {
id: usize
}
lazy_static! {
static ref VEC : RwLock<Vec<Box<Item>>> = RwLock::new(vec![
Box::new(Item { id: 0 }),
Box::new(Item { id: 1 }),
Box::new(Item { id: 2 })]);
}
fn get_a_certain_item() -> &Item {
& VEC.read().unwrap()[1]
}
fn get_a_certain_item_by_id() -> usize {
1
}
fn main() {
// this works, but verbose
let ref_a = {& VEC.read().unwrap()[get_a_certain_item_by_id()]};
// this doesn't work
let ref_b = get_a_certain_item();
}

Compiling the code gives this error:
error: missing lifetime specifier [E0106]
fn get_a_certain_item() -> &Item {
^~~~~
help: run `rustc --explain E0106` to see a detailed explanation
help: this function's return type contains a borrowed value,
but there is no value for it to be borrowed from
help: consider giving it a 'static lifetime
In Rust, lifetimes are simply parameterized placeholders, just like generic types (see this answer for more info). That means that every returned reference must have a lifetime that corresponds to some input reference. Your function doesn't have that.
If it were possible for the lifetimes to not correspond, then you'd be able to have code that returned a lifetime that could be whatever the caller wanted it to be. This is generally nonsense, as the reference will stop being valid at some point and thus you'd be breaking the memory safety rules.
What I just said is true, but leaves off one small but important corner case: the 'static lifetime. This is a built-in lifetime that corresponds to items compiled into the code. Normally this means global variables defined with static or references to literal values. These values exist before main is called and are destroyed after main has ended. It is impossible to actually create such values during the runtime of your program.
Note that the error message makes reference to the 'static lifetime. However, if you just add this lifetime, you will get a different error:
error: borrowed value does not live long enough
&VEC.read().unwrap()[1]
^~~~~~~~~~~~~~~~~~~
note: reference must be valid for the static lifetime...
note: ...but borrowed value is only valid for the block at [...]
This is because the compiler cannot ensure that the value will last for the entire length of the program. In fact, it can only ensure it will last for the duration of the function call.
As the programmer, you may know (or think you know) better than the compiler. That's what the unsafe escape hatch is for. This allows you to do things that the compiler cannot verify. It does not allow you to break memory safety; it's just up to the programmer to ensure memory safety instead of the compiler.
In your case, if you can guarantee that items from the vector are never dropped, and that you always use a Box, then it should be safe to pretend that references to the Item are 'static.
A Boxed value is allocated on the heap, and the memory is never moved after the initial creation. Since items in the vector are not dropped, the Box will never be freed.
Here's a verbose example of implementing the method:
fn get_a_certain_item() -> &'static Item {
// Best practice: put a paragraph explaining why this isn't
// actually unsafe.
unsafe {
let as_ref: &Box<Item> = &VEC.read().unwrap()[1];
let as_ref2: &Item = &**as_ref;
let as_raw = as_ref2 as *const _;
let unsafe_ref = &* as_raw;
unsafe_ref
}
}
Converting the reference to a raw pointer throws away the lifetime. When we reconstitute it we can make up whatever lifetime we want.
For what it is worth, I don't think it is worth it in this case. If I actually have a global variable, I want that to be front-and-center in my code as I view it as an ugly wart. I'd much rather create a type that owned a RwLock<Vec<Box<Item>>>, make a global of that type, then parameterize my code to accept a reference to that type. Then I lock the global when I need it and pass the reference into functions.

I can ensure that I won't mutate those elements once they are inserted
You can, can you?
But even if you really really can ensure that the vector will never be mutated, it's still a good practice to use the type system in such a way as to make the illegal states and operations impossible.
In this case, you can hide the Vec in a module, then any user of that module won't be able to mutate the Vec and ruin your invariants.
#[macro_use]
extern crate lazy_static;
// Hides the gory details from the user of the API.
pub mod items {
use std::mem::transmute;
pub struct Item {
pub id: usize
}
lazy_static! {
static ref VEC : Vec<Item> = vec![
Item { id: 0 },
Item { id: 1 },
Item { id: 2 }];
}
pub fn get_an_item (idx: usize) -> Option<&'static Item> {
// As Shepmaster has pointed out, Rust is smart enough to detect
// that the vector is immutable and allow the 'static lifetime:
VEC.get(idx)
// And when it isn't that smart, we can use `unsafe`
// to tell the compiler that the 'static lifetime is okay:
/*
match VEC.get (idx) {
Some (item) => {
// `unsafe` means "safe, scout's honor", cf. http://doc.rust-lang.org/book/unsafe.html
let item: &'static Item = unsafe {transmute (item)};
Some (item)
},
None => None
}
*/
}
}
fn main() {
let ref_b = items::get_an_item (1) .expect ("!1");
assert_eq! (ref_b.id, 1);
}
Note that, since the Vec is immutable, there's no need to Box the Items. This might be nice from the data-driven, cache locality perspective.
And if a user of this module tries for an undefined behavior with a code like this items::VEC.push (items::Item {id: 3}); he'll get an "error: static VEC is private".

Related

What expressions are allowed as the array length N in [_; N]?

Please consider the following minimal example in Rust:
const FOOBAR: usize = 3;
trait Foo {
const BAR: usize;
}
struct Fubar();
impl Foo for Fubar {
const BAR: usize = 3;
}
struct Baz<T>(T);
trait Qux {
fn print_bar();
}
impl<T: Foo> Qux for Baz<T> {
fn print_bar() {
println!("bar: {}", T::BAR); // works
println!("{:?}", [T::BAR; 3]); // works
println!("{:?}", [1; FOOBAR]); // works
println!("{:?}", [1; T::BAR]); // this gives an error
}
}
fn main() {
Baz::<Fubar>::print_bar();
}
The compiler gives the following error:
error[E0599]: no associated item named `BAR` found for type `T` in the current scope
--> src/main.rs:24:30
|
24 | println!("{:?}", [1; T::BAR]); // this gives an error
| ^^^^^^ associated item not found in `T`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `BAR`, perhaps you need to implement it:
candidate #1: `Foo`
Whatever the answer to my question, this is not a particularly good error message because it suggests that T does implement Foo despite the latter being a trait bound. Only after burning a lot of time did it occur to me that in fact T::BAR is a perfectly valid expression in other contexts, just not as a length parameter to an array.
What are the rules that govern what kind of expressions can go there? Because arrays are Sized, I completely understand that the length are to be known at compile time. Coming from C++ myself, I would expect some restriction akin to constexpr but I have not come across that in the documentation where it just says
A fixed-size array, denoted [T; N], for the element type, T, and the non-negative compile-time constant size, N.
As of Rust 1.24.1, the array length basically needs to either be a numeric literal or a "regular" constant that is a usize. There's a small amount of constant evaluation that exists today, but it's more-or-less limited to basic math.
a perfectly valid expression in other contexts, just not as a length parameter to an array
Array lengths don't support generic parameters. (#43408)
this is not a particularly good error message
Error message should be improved for associated consts in array lengths (#44168)
I would expect some restriction akin to constexpr
This is essentially the restriction, the problem is that what is allowed to be used in a const is highly restricted at the moment. Notably, these aren't allowed:
functions (except to construct enums or structs)
loops
multiple statements / blocks
Work on good constant / compile-time evaluation is still ongoing. There are a large amount of RFCs, issues, and PRs improving this. A sample:
Const fn tracking issue (RFC 911)
Allow locals and destructuring in const fn (RFC 2341)
Allow if and match in constants (RFC 2342)

initializer element not constant?

I am relatively knew to C and only learning pieces of it to publish a Pebble C/PebbleKitJS app to track buses. So far I have the data being processed on a Node server, and I am getting ready to have the data processed by a JS File. MY one problem however lies within the C Code.
This code process data stored in a Key Dictionary sent from JS and assigns it to a variable for use below. By using #define var 9, I can successfully have the .high value set to 9. But through an int var, it fails and throws the error:initializer element not constant?? .
What does this error mean, and what exactly is the difference between static and constant if i don't define it. apparently static vars don't return anything? Some help would be much appreciated.
UPDATE: The problem still isn't fixed. The following new error message occurs in addition to the initializer one. error: (near initialization for 's_data_points[0].high')
int key0_buffer;
void process_tuple(Tuple *t)
{
//Get key
int key = t->key;
//Get integer value, if present
int value = t->value->int32;
//Get string value, if present
char string_value[32];
strcpy(string_value, t->value->cstring);
//Decide what to do
switch(key) {
case key_0:
//Location received
key0_buffer = value;
break;
}
}
static WeatherAppDataPoint s_data_points[] = {
{
.city = "San Diego",
.description = "surfboard :)",
.icon = WEATHER_APP_ICON_GENERIC_WEATHER,
.current = 110,
.high = key0_buffer,
.low = 9,
},
};
Try this instead:
enum { key0_buffer = 9 };
C doesn't provide for runtime computations while initializing global variables. (The concept does exist as a C++ feature called "dynamic initialization.")
The execution model is that it can store all the bytes of global variables in ROM, and then copy any modifiable variables into RAM together with a single memcpy. Assigning one global to another would be more complicated.
#define allows you to substitute the text 9, which is a constant expression.
Many frown upon using text substitutions to avoid variables as primitive, unnecessarily low-level, and potentially inefficient. In this case though, the results should be the same.
In C, enum constants have type int, so they are a suitable substitute. You're out of luck for other types, though.
There is a key difference between the code in your function and the code lower down that defines the static variable. The function code is executable -- these lines are going to get run when the function is called.
Your static declaration of WeatherAppDataPoint is just telling the compiler to create the static variable. The initialization values you are placing in that declaration tell the compiler what value to initialize this data to. That is why they must be constant -- these are the values that get loaded in before anything gets executed.
The #define statement just tells the preprocessor to replace all instances of "var" with the string "9". It is literally the same as a cut and paste operation in a text editor. This gets done before the compiler ever sees the code. This is why you have no problems with that; the compiler sees a literal constant, just as if you'd manually typed the "9" directly into the source code.
In 'C', variables don't return things, they store them. Only functions return things. If you want to have an integer declared somewhere, and then assign it to the value of your static variable, that is an actual executable line of code that will need to occur inside of a function somewhere (ie inside of your process_tuple function). The lines of code below the static declaration aren't executed at run time, they just setup the initial state of the program and tell the compiler how big the variable is.

What is the purpose of Rust's function parameter syntax over C's?

Weird title, anyway, in C function parameters are as follows:
void func_name(int a, int b) {
}
However in Rust:
fn func_name(a: int, b: int) {
}
Is this just a preference in syntax and was appealing to the creators of Rust, or is this for a specific purpose that I don't know about? For example, Go has "optional semi-colons", but they are actually to show when an expression ends. Please bare in mind that I'm a complete novice at Rust, so if you try to provide some fancy examples in Rust I probably wont understand :(
The declaration of a function argument is just a special case of variable declarations in Rust, therefore the answer to your question lies in variable declaration in general.
Let us start with C:
a b = 1;
a = 2;
From a grammar point of view, C is not quite regular:
in a b = 1;, a is the type and b is the name of a new variable being declared (and initialized)
in a = 1;, a is the name of a variable that was declared previously and is now either initialized or assigned a new value (overwriting the previous one).
Therefore, in C, knowing whether a is a type or a variable name requires looking ahead (ie, if followed by another variable then it's a type, otherwise it's a variable).
Now, in Rust:
let a = 1;
a = 2;
The syntax for introducing a new variable requires using the let keyword, there is no ambiguity and no need to look ahead to disambiguate. This is all the more important because of shadowing in Rust (let a = ...; let a = a.foo;).
The question was about types though, so let's extend the example:
let a: b = 1;
a = 2;
In this case, again, there is no need to look ahead. Immediately after let comes the variable name, and only after parsing a : comes the variable type.
Therefore, the syntax of Rust is simply meant to avoid look ahead (Rust aims at having a LL(1) syntax) and the syntax of function arguments simply follows the regular syntax.
Oh, and by the way, not all arguments have a type:
impl Foo {
fn doit(&self);
}
In normal Rust code a variable is declared this way:
let x : i32 = 0;
The C style is not possible because the type is optional, so the former is equivalent to this one:
let x = 0i32;
You need the let keyword to declare the intention of declaring a name.
In a function declaration the type is mandatory, the initialization is not allowed and the let keyword makes no sense. Other than that the syntax is the same:
fn foo(x : i32)
It would be weird to have a different syntax for declaring local variables and function arguments, don't you think?

How do I create an array of unboxed functions / closures?

Editor's note: This question was asked before Rust 1.0 and some of the syntax has changed since then, but the underlying concepts remain. Some answers have been updated for Rust 1.0 syntax.
I'm new to Rust and trying to do something with closures which is trivial in JavaScript, Python, etc. but I am running into lifetime issues in Rust. I understand the error message, but it leads me to believe what I want to do is pretty hard in Rust.
I just want to create an array of functions, a, such that
a[0] is the function returning 0
a[1] is the function returning 1
...
a[9] is the function returning 9
I tried:
fn main() {
let a : [||->uint, ..10];
for i in range(0u, 10) {
a[i] = ||{i};
}
println!("{} {} {}", a[1](), a[5](), a[9]())
}
But I got a lifetime error. The reported error was "cannot infer an appropriate lifetime due to conflicting requirements" for the functions in a because the lifetimes cannot outlive the while block so that the closures cannot outlive their stack frame, which of course they would because I am invoking them in println!.
I'm sure there must be a way to build up this array of functions, but how?
You need to use move || i.
move implies that this closure will take i by value rather than by reference. By default, these closures would only take references to i. In your case it is forbidden as the lifetime of i is limited to the body of the loop.
Also, Rust will complain that your array may not be fully initialized. To avoid it, you can either use a Vec<_>, or use std::mem::uninitialized:
fn main() {
let mut a: [_; 10] = unsafe { std::mem::uninitialized() };
for i in 0..10 {
a[i] = move || i;
}
println!("{} {} {}", a[1](), a[5](), a[9]())
}
It is possible to collect multiple closures from an iterator into a Vec:
fn main() {
let a: Vec<_> = (0..10).map(|i| move || i).collect();
println!("{} {} {}", a[1](), a[5](), a[9]());
}
The move keyword causes ownership of i to be transferred to the closure.
See also:
How do I collect into an array?

Swift optional Array property is immutable?

I am constructing an array of booleans to store the state of the sections in a UICollectionView. It is a variable stored as a property of my UIViewController:
var _weekSelections : Array<Bool>!
Then, in a function called by loadView(), I construct the array and assign a value to the first index:
_weekSelections = Array<Bool>(count:_weekCount, repeatedValue:false)
_weekSelections[0] = true
The value at index 0 remains false! The array is constructed, and has multiple elements, but any assignment that I make to an index does not affect the value stored at that index, even if I check the value on the very next line of code. I know that Swift makes a copy of an array if I perform an action that may change its length, but I don't think this is a case where a copy would me made. The only way I can get any value to change is if I manually create a copy as follows:
var copy = _weekSelections
copy[0] = true
_weekSelections = copy
Am I missing something obvious or could this be a strange bug?
For the sake of having my code on SO rather than Pastebin, here's my observation. This looks like some kind of bug or unexpected behaviour when using an optional array in a Swift class derived from an Objective C class. If you use a plain Swift class, this works as expected:
class Foo {
var weekSelections: Array<Bool>!
func test() {
weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]) // Prints "true"
}
}
var foo = Foo()
foo.test()
However, if you derive Foo from NSObject:
import Foundation
class Foo : NSObject { // This derivation is the only difference from the code above
var weekSelections: Array<Bool>!
func test() {
weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]) // Prints "false"
}
}
var foo = Foo()
foo.test()
Even in this case, if you do your weekSelections initialisation in an initialiser, then it works:
class Foo : NSObject {
var weekSelections: Array<Bool>!
init() {
weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]) // Prints "true"
}
}
var foo = Foo()
Personally, I'd say that this is a bug. I can't see anything in any documentation that would explain the difference in behaviour when derived from NSObject.
I also can't see anything that says that optional array properties would be immutable. This would be especially strange when you consider that "immutable" arrays are actually mutable in Swift, i.e. this:
// Use "let" to declare an "immutable" array
let weekSelections = Array<Bool>(count: 10, repeatedValue: false)
weekSelections[0] = true;
println(weekSelections[0]); // Prints "true"; arrays are never really "immutable" in Swift
...works fine, and is currently documented as being valid, even if it seems a bit odd.
Personally, I'd use whatever workaround you can and raise a bug with Apple, to see what light they can shed.
Not an explanation, but a workaround. The issue isn't with the count:repeatedValue initializer, but rather with the array being assigned to an optional variable. From what I can tell optional arrays can only use accessor methods and not mutator methods--effectively they're immutable. Temporarily assigning _weekSelections to a non-optional variable before attempting to change its contents (and assigning back to _weekSelections when done) will work. Please note that this seems to create a new array (with the same elements) on assignments, so there may be memory issues to consider if the array is very big. Of course, simply using a non-optional variable in the first place will also work.
As for why optional arrays aren't mutable, that may be a bug or there may be some esoteric reason for it I'm not fathoming. Anyone else have a plausible-sounding theory?

Resources