If I leave out the <'a> on the definition and the &str, the compiler tells me I need a named lifetime on them.
If I put in the named lifetime, the compiler tells me that the signature of iced::run isn't correct.
I presume that the problem is at least in part the signatures on my update and wview declarations, so I am including those here as well:
and I have defined Default and Clone traits for that. The lifetime marks on that were added because in an earlier stage the compiler told me I needed them. I may have misunderstood the error.
iced::run requires 'static everything, so you're going to need to refactor to not have lifetime laden structs, e.g. using String instead of &str or perhaps Rc<str>.
I a clearly still missing something. I edited things to get rid of the lifetimes, and mad ethe view and update methods into methods on the state object (RoloGuiState). The key field in the graphical state is the anchor for the underlying data, the RolodexBase. In order to allow various elements of the data to refer to their parent, I actually work exclusively with an Rc. That way, the other references can be Weak. But.... when I have the key state field:
rolodex: Option<Rc<RolodexBase>>,
the compiler promptly tells me that I need an explicit lifetime on that. If I put that in, then it starts wanting lifetimes on lots of other things, and I am in the mess I need to avoid.
...you can't pretend RolodexBase<'_> and RoloRightGuiState<'_> don't have lifetime parameters, any more than you can pretend Vec<T> doesn't have a type parameter. Your choices are
Also get rid of the lifetime parameters on RolodexBase<'_> and RoloRightGuiState<'_> as well, and so on, recursively
This may involve a bunch of refactoring to get rid of whatever borrowing is going on that made the compiler suggest the lifetime annotations
Use RolodexBase<'static> and RoloRightGuiState<'static>[1] (which is your only choice if they are foreign types)
This may involve a flood of borrow check errors because you're attempting to borrow for &'static and may or may not workable at all
this is equivalent to trying to use RoloGuiState<'static> without changing the definition âŠī¸
Everything is in one crate. (well, except for iced, and probably later Serde).
I could probably get rid of all the &str in RolodexBase (and person), making them all String, and putting up with copying too many times. I can't tell from your comments if the necessary uses of RC, in RolodexBase use of RefCell<Vec>, and in person, use of Weak will still cause the compiler to want me to specify lifetimes for them. If just changing the &str to String will do the job, I will put up with the copying.
Yours,
Joel
Just some thoughts, because I would need more info about your project and what you are trying to solve, to give specific advice. From my experience and what I have learned from others in the iced discord, references or ref counted values Rc, Arc or even internal mutable types are almost never what you want in your app state. The base idea of ELM architecture is, that the app state is the single source of truth and thus should own the data. All modifications should be done via messages that are handled in the update fn. If you need to fulfill the Clone bound on messages, use an Arc.
If all you need was read-only string data, and using String would clone too much for your tastes, Arc<str> or Rc<str> may be a solution (they make clones non-allocating/cheap). (Or &'static str, or Cow<'static, str>, if you have all/mostly literals.)
I am using Rc only to get Weak references to the common root of truth. (Which ends up in the iced state structure. I am using interior mutability (RefCell) for all changes to that structure, so the Weak references remain valid, and no one needs a mutable reference to the source of truth. Yes, all changes to any of the data come through the Update method, and are effected in the State. I really don't want to drop the parent references, as they help me ensure the consistency of information. (All the references between data components are done via ids owned by the root of truth, so I don't need any other Weak<> cases. I had already realized that rather than mutating the subsidiary elements (by having them RefCell internals) it is clearner to just build new instances and replace them in the master, since all teh references through IDs will come out right. It would be really frustrating if the GUI required me to remove the parent references that help provide error checks. (Conceptually, there could be two Rolodex open at the same time. I don't need that, but I hate to design such that it is impossible. If the People can't point to the database root, then itnerpretting the IDs for itner-person references becomes fraught.
Yours,
Joel
Some of the things you mention sound like problems most of the new iced users are fighting with. References through IDs should not be a problem, that's a common used strategy in iced apps. From what you write it seems your data is coming from some kind of database, but I'm just guessing here?
If you project is open source I could have a look.
Otherwise it seems that the chance of getting help for specific problems is better in the iced discord or the (new) iced zulip. At least that's my experience. Feel free to ping me here or there.
For me personal, icebreaker from the maintainer of iced helped a lot to understand how to structure my iced apps. It's not as overwhelming as halloy.
Don't put temporary references in structs. This is not a typical thing to do, but a rare special kind of struct. In 99% of cases trying to put a reference inside a struct is simply a design error.
If you just need to store a string, use String in structs.
Structs with temporary references inside stop being a normal data types that you could freely use. They become temporary views themselves, and become forever restricted to the fixed scope of the loan, with no ability to extend it. This is infectious and unavoidable.
Lifetime marks data that is not stored in a struct. Whenever you have &'a str it means that the string in not here, the data is missing from the struct, and is stored elsewhere instead. Because of this dependency the whole struct becomes permanently anchored to wherever that "elsewhere" originates from. If you're not deliberately using this feature, it almost always ends up being a local variable in a function and you're trying to anchor your whole program to one variable that will be automatically destroyed a second later.
These restrictions are for certain design patterns like lock guards or iterators, that are meant to be tied to the object they're borrowing from and restrict its usage. But in case of structs that are supposed to just store a string, asking for restricted lifetime makes no sense - you're not trying to freeze access to some local variable somewhere, and you're not trying to prevent use of the struct outside of the function where it has been created.
I will look at icebreaker. Would be happy to chat on iced Discord. I can't seem to find it from my discord client, and when I use the link it says that there are no text channels I have access to.
The application is a quirky rolodex. So it is mostly a data representation, a guid to review / modify it, and some means fo storing the result (presumably Serde).
Yorus,
Joel
PS: I am an old programmer, new to trying to think the way RUST wants me to. I do see the value in Rust's approach, which is why I am trying to use it.
Okay. Sounds like I should just change all my &strs to String. Which may or may not fix my iced difficulties, but will make other things work better in the long term.
You probably need to use the official invite link from the iced website - upper right corner. Be aware, that the project is currently trying out zulip and that all chat and discussions will move over there eventually.
Posting in case some other newcomers makes the same mistake I did.
Thinking about this over night, I am pretty sure that the key to most of my misunderstanding is that I am looking at constructors as if they were from some other langauge, where things appear on the heap. For good reason, Rust puts things on the stack whenever it can, which is most of the time. Once I get that through my head, things start making more sense. And this was probably so basic that the folks being helpful did not even realize that I was missing that. After all, I had read it.
Thanks for all the help,
Joel
Rust HATES this., and cycles in general. You can use Rc/Arc and weak, but it's a pretty miserable experience in most uses.
You have a few options to "squash" your data so there's no cycles: one is that you don't persistently store the parent references, but recreate the "path" to the current item while you navigate to it. This is a bit tricky to get right if you're not new, but it's very clean.
Another is the general Rust solution to making a reference persistent: use an index instead. In the simple case of a homogenous tree of nodes, instead of a root node with a vector of children nodes, you can use a flat vector of nodes with a root index (possibly implicitly the first), and a vector of children node indices. Be careful, this effectively becomes you recreating a manual memory allocator (or garbage collector) if you're doing a lot of adding and removing nodes, though. If you're only adding, this is a pretty great approach, though, and the performance is generally much better than for referenced nodes too for free (due to memory locality)
There's other fancier things you could try too, but this, designing your data to avoid it being a soup of references, is basically the Rust problem. On the plus side, it's all uphill from here!
I am trying to see if I cna make it work with RC. If not, or even if it does once I have gotten it clean, I can probably get rid of the parent references because the iced State block handling will ensure the parent is always well-defined and available. I would be giving up the two rolodexes use case, but that was highly speculative so I can live with losing it. And it woul also get me out of the RefCell stuff I am currently using. Clearly, ijust dropping the parent reference is what Rust wants me to do.
Admittedly, part of why I am using Rc<> and Weak<> is that I am trying to also understand what I have to do if I am trying to handle network graphs. And the answer seems to be again to use indirect referencing through ids in whatever parent is holding it all together. (I tend to think about everything in terms of "how useful is ti for router control logic"" since I have been working with that for more than 40 years.
Yours,
Joel
Another question that is probably obvious once I know what to look for...
One of the reasons I ended up using a lot of ^str in my structures was that I am building a lot of thigns out of quoted strings. Which are as I understand "a" is an &str.
I seem to have mislaid the basic method to get a String from taht. And, more useful would be a way to turn a vec<&str> into a vec (presumably by copying in Heap space?)
Thanks,
Joel