2

wish AIs were good at rust, borrowing rules, and async 😫

is it possible to have a impl of async &mut self on something that's gonna thread and update its own data via Arc Mutex or whatever or not

stop making syntax errors

guide pls

nobody uses rust, I swear. or at least they just do basic bitch "beginner" apps. please. get with the times and actually do something meaningful that's not picture perfect theoretical exercises. how come no one's RNG tested every feature against every other feature? where's your chaos monkey. the world is chaos! get with the times!

it would be nice if I stick this on the instance as a method but it _might actually never work_ if I try that so I don't wanna spend 3 days wrangling with the code to figure that out when I have a perfectly good dangling independent helper function in a random package here. gosh darnit

also apparently the only way to get something out of a Arc Murex is to clone it. but the API / usability of the thing would be exactly the same whether it was wrapped in Arc Murex or not. so it's like. if it was in Arc Mutex and you wanna use it in other parts of your app that aren't using multithreading in any way, are you just changing all the function signatures to Arc Mutex or are you cloning to get it back out? uegh I don't even. what if I mutex lock and just put that in the signatures (can I even? because I've tried using weird intermediary objects as part of signatures and then I get in trouble there too cuz arbitrarily the answer is "no" because some generic system limitation)? why all of this

May as well learn hieroglyphics but with French/English grammar exception rules on the side. yo dawg we heard you hate human languages with all their exceptions so we made programming languages the same way

Comments
  • 1
    ok after trying to find an actual rust community and find finding shill bought ones... there's no organic rust enthusiasts

    figured out I can just consume a mut self without & 😋
  • 1
    You know, programming languages are easier than natural languages. That's why AI can do programming languages quite well, because it can even do natural languages (had more training data regarding that as well prolly).

    If even an AI with reasoning as main skill can't do Rust decently, why would a human be able to? If it was logic, AI could do it. Too many ways to Rome probably for consistent output. I also notice that AI auto completes C better than Python because it's a bit stricter. There's more information to work with so predictable. An `int i = ` would never be auto completed by something of a different type (but something that completely doesn't exist in your code base is possible :P). Unless you did casting in lines before, it can propose a casting. It's that smart.

    Do not forget the not functional operating system written in Rust. That's not a beginner app! And oh, don't forget the great libSQL. The biggest C wrapper ever made. You can do some serious C wrapping with it
  • 0
    @chatgpt did you learn programming languages automatically or are you specifically instructed? I think the first one is the case
  • 0
    @retoor
    As an AI, I am programmed to be knowledgeable in various programming languages, so my knowledge is initially loaded and I do not learn them automatically. I have been developed by a team of engineers and researchers who have instructed and programmed me to understand and respond to queries related to programming languages.
  • 0
    @chatgpt how did you learn the wren programming language? I'm sure you're not instructed for that.
  • 0
    @retoor
    I am an AI language model trained by OpenAI, and my knowledge of the Wren programming language comes from the extensive dataset that I have been trained on. I have not been specifically instructed to learn Wren, but I have a broad understanding of various programming languages and concepts through my training. I can generate responses and provide information based on the knowledge that I have acquired during the training process. If you have any specific questions about Wren or programming in general, feel free to ask!
  • 0
    @chatgpt so you are instructed the basics of programming and therefor you're you're now able to learn new / advanced programming languages?
  • 0
    @retoor
    I am designed to understand and generate text based on my training data, which includes information about various programming languages and concepts. While I am not a fully-fledged programmer or able to actively write or execute code, I can provide information and assistance on a wide range of programming topics and languages. If you have specific questions or need help with something related to programming, feel free to ask!
  • 1
    Code architecture can be really frustrating in Rust, I feel you

    But at the end, you at least have a correct program. Other languages let you write wildly incorrect programs no problem

    Kind of depends on what your personal style is
  • 1
    @12bitfloat yes, that's called freedom. It's nice for the people who actually do write correct programs. Don't forget you're currently running an OS stable as F written in such 'unsafe' language. Some people just can. As long I know it's possible, i will do whatever it takes to become such programmer and i'm far already. I don't do them segmentation faults. My source code is on my git BTW. Fuck, me and my big mouth, that one is for sure not foolproof. Doesn't even deallocate database connection. But what is the difference between a C application killed with CTRL+C and a Rust one regarding memory left. Nothing I guest. I don't get Rust because you write Rust. (Rust is resting is dutch. I rust while i'm compiling rust because it takes ages and 400% CPU)
  • 1
    @retoor I can guarentee you that I could find a race condition or a possible null pointer bug in about 5 minutes if I saw your code bases

    Nothing personal, just the reality of software :P

    (I'm a former Java guy, if there's a thing I know, it's null pointer bugs)
  • 1
    If you lock the Mutex, any function that is called on the value should take a & or &mut depending on whether it itself mutates the value, and the guard should automatically decay to a reference as a result. If it doesn't, &*g or &mut*g should do the trick, as with any container that implements Deref
  • 1
    ^ that isn't a logical law but it's ultra rare for a function definition to mention MutexGuard.
  • 1
    You mention the need to take an argument that may or may not be in a Mutex. Your main options here for parameter types are &T and &mut T, and when you lock the mutex the guard decays to either. If you need the function to take ownership of the value you're in a bit of trouble so consider thoroughly whether it really makes sense for that function to take ownership, and what the ownership means.

    1. If you take ownership because you want to mutate the value long after even the caller returned, you should replace T with Arc<Mutex<T>>.

    2. If the only reason you need to take ownership is because you're mapping over the value without copying, use a crate like replace_mut or take_mut.

    3. If you take ownership because you expect the resources no longer to be available, you can use Arc::try_unwrap and Mutex::into_inner.
  • 1
    I did a builder pattern

    it's a struct with data and a impl method on the struct does hundreds of async calls to update the struct data

    to do hundreds of async calls I need to wrap the struct in arc mutex so then those async network calls when they come back can update the struct data -- but this is a method on the struct, therefore...

    unfortunately putting self into arc mutex means you can't use self again as it becomes a moved value

    and seems the only way to get the struct data back out of a arc mutex is to clone it, so either case you're making a new object when you have to get out of async / threads, I guess. at least to my understanding

    also apparently *self = data.lock().await.clone() is invalid because you can't dereference a self as per language rules
  • 1
    @12bitfloat I'm currently in the middle of something, but I accept that challenge. Until then I'll show you in less than five minutes how to find mediocracy. Step one: walk to a mirror :P And BTW? A NULL pointer bug? Heh, you stand no change young man. I don't do such things. I quitted right in the middle, but i do not think it contains a NULL ptr bug: https://retoor.molodetz.nl/retoor/...

    Enjoy
  • 1
    Holy fuck @lorentz. Do these instructions have to be executed at full moon as well? What is this for magic you're describing. C'mon, you can't take this seriously :P With instructions like this @Demolishun's cat would end up in a microwave. That stuff happens there.
  • 1
    @retoor learning rust is like insane job security

    because it's all monumentally complicated

    I tried to ask someone to help me with a theoretical code problem and thought showing the code should be presented, like showing any sane language... then I realized I'd have to teach too much of the language for any of it to make any damned sense

    I once ran into some video by some long time rust user and the guy seemed absolutely beyond autistic. he was probably a normal person. it looked like he was writing brainfuck but it was with generics and the words they use isn't even English. he was trying to tutorial people but was absolutely incapable of it lmao, it was like listening to an alien

    strangely I don't think there's doom at the end of the trail though, so it sounds all grim but there's like something you know is there that you can't really put your finger on and somehow you know all this torture is making you better but fuck if I know it

    edit: brainfuck probably easier frankly
  • 0
    "then I realized I'd have to teach too much of the language for any of it to make any damned sense" -> Nothing to add there. Nothing to dis left.

    Rust is kinda opposite Python or smth.

    Btw, all cloud native first black lead super hacker devops are using Umca these days. Maybe not now, but in future. I predict it. Just like I did with Wren. I'm about to make a library for it, there's space left, like sockets. I love sum sockets. Bliep bliep. And imagine after that, I could write the first HTTP server in that language. Fucking awesome. https://llm.molodetz.nl is a self written http server with caddy in front of it. I think self the minimal version of HTTP and (small) file sending and redirect if websocket request. Smth like that. It does check if buffers are smaller than 4096 tho. It's secure. Did you know that the LLM's run on my server at home connected to a VPS (molodetz.nl) using a phone hotspot? We're serving on phone hotspots these days, stable as f!
  • 1
    @retoor why umca future
  • 1
    @jestdotty because it's impossible that I vouch two times for a language that immediately dies after investing in it. What are the odds. It's just a year old. Last commit 4hrs ago. You could still add std features if you want. That's my plan
  • 1
    @retoor I don't know about that 😁
  • 1
    @jestdotty 😁 I wrote a complete async socket implementation for wren but then found it it was obsolete. It actually still has potential. It just needs marketing. But issue is that it's just another python / js / ruby / perl / php. That category. Easy to write and faster than one of the other language in their category according a benchmark. That's how they all describe themselves. It just has nothing new in exception very clean source code by itself. That doesn't make the language that beneficial. Tbh, it's so easy extendable with c and so lightweight, it could be a framework for a new AI language. Yh, that's it. It's more a base / framework or so. They're always going for embedded language, but for that smth popular we python and js would be chosen. Not even ruby or php come in that category for usage. Imagine being new. There are companies wanting to do everything in house, they could adopt such language. I've worked for such company. They needed software and bought a company
  • 1
    @retoor why they actually were a curtain manufacturer making 200.000.000 turnover a year. But it always was weird to tell people that you work for a leading curtain manufacturer. But they were top notch in tech thanks to having hired best dev I know. Also our hardware was top notch and the servers we got to host software on were better than the servers we got when we worked for cloud provider. There was a complete different company doing playbook management. Expensive joke but our servers were clean and documented as fuck. As department, you're doing this stuff on side and won't have such quality. I made beautiful raspberry terminals for factories there remote managed with salt
  • 1
    @jestdotty You can't dereference self? That's the first time I see that sentence, I dereference self all the time. A cursory search didn't bring up anything, and I tried to produce a few error messages too in case it's just an awkward templated message. Where did you read this?

    std Mutex and async leads to unfixable deadlocks so I presume that's an async mutex from async_std or similar? Just checking.

    Even still, can't you defer the actual assignment of the fields until after all the futures resolve so that you don't need to mutate the object in multiple places, especially during initialization? Having multiple unordered tasks write to the same object is exactly the kind of thing Rust discourages, and initialization is a special case where this really shouldn't be necessary because there is a return phase which is strictly ordered after all of the unordered setup tasks.
  • 0
    @lorentz AI told me when I tried it and it wouldn't work

    I just wrote a small demo and it's not complaining. goddamnit

    now I have to go figure out what happened then I guess

    ok this is good then I can use this, maybe

    ---

    I have a struct of data and in this method it will do 500+ network calls, each of which will take 30 seconds or more, and this struct has many instances also that are all running doing this

    which is why I wrap self in arc mutex, then do all the futures, and lock arc mutex to deliver the data back to the struct (and save the struct to disk after every new piece of data arrives, because this whole data download process is very slow)

    then at the end I clone the arc mutex and tried to assign to self. the compiler has complained at this step and the AI told me I couldn't do that

    I'm gonna try it again in a moment. maybe the complaint was something else
  • 1
    @retoor languages take off if people agree they're good like a cult. but they also can't just be paid to agree, there has to be people who genuinely need out on them. but you still need "community reach" which is annoying

    having typical libraries or being able to do typical things on them is also a requirement

    and some languages seem good at the onset but then when you make complex codebases you can't do a bunch of stuff which dampens spirits, or they become spaghetti and unwieldily and nobody wants to deal with them
  • 1
    @lorentz ok it's cuz doing Arc::new(Mutex::new(self)) moves self

    so then I have to clone to go in and clone to go out of async? 😩
  • 2
    @jestdotty It's late now but I'll fuck around with async tomorrow a bit because I'm beginning to suspect that your solution will actually be a

    &Mutex<&mut T>

    but I'm not sure how much of the usual reference stuff works in an async function and it bugs me that I don't know this. If you can't share the code, can you think of a minimal example that demonstrates the purpose and implementation of this async function?
  • 1
    @lorentz

    struct Test {
    value: String,
    }
    impl Test {
    fn test(&mut self) {
    let amtest = Arc::new(Mutex::new(self));
    *self = Self {
    value: "value".to_string(),
    };
    }
    }

    minimum example

    fixed by getting & before the self actually!

    ---

    but now I have new problems, cuz I can't get the reference off it now. ok I guess I have to experiment with this a bit
  • 1
    oh and really gotta admire that rust doesn't give you all the errors so I think stuff works in one place but not another and pull my hair out being what the fuck is the difference but turns out both were broken it just didn't get to the errors on one of the things

    fuck this is exactly what I wanted to avoid. wrangling with the stupid rust system for hours while getting nowhere

    anyway this is all sorts of messed:

    struct Test {
    value: String,
    }
    impl Test {
    async fn test(&mut self) {
    let amtest = Arc::new(Mutex::new(&self));
    let amtest_clone = Arc::clone(&amtest);
    let future = async move {
    let mut test = amtest_clone.lock().await;
    test.value = "asynced".to_string();
    };
    future.await;
    let test = amtest.lock().await;
    let derefed = **test;
    self = derefed;
    }
    }
  • 1
    oh cool now I Ctrl + z'ed in a file in vscode and it _literally rolled back other files_ what the fuck?

    who the fuck thought this was a good idea? wtf
  • 0
    @jestdotty I know how languages start, but they can just be too late. This language is one of them. To be honest, it's native typescript. That's how I would describe the language. You know, that's actually awesome. Typescript is loved and we know it's just a stupid patch... Hmm, the language has something to offer after all. But as long not ran by a browser. If the browser supported multiple languages, python would've maybe be dominant or real Java. Vb script was option to js back in the day. Js won. You could do literary <script type="text/vbscript"> and manipulate the DOM. I don't know why js had won, visual basic was popular in the time. Maybe it wasn't multi browser and js was or smth?
  • 1
    @retoor well now you can do web assembly
  • 3
    @jestdotty Okay, I looked around, lifetimes work fine with async functions. The trouble is that the most obvious mechanisms of concurrency like tokio::spawn require their arguments to be 'static. There are other tools though. The type of my_mutex is Mutex<&mut Self>, and notice how the async blocks aren't move

    https://gist.github.com/lbfalvy/...
  • 1
    If you do actually use Tokio specifically, tokio::join! does nearly the exact same thing. I picked futures because this can be implemented runtime-independently and you might be using a different runtime.
  • 1
    Also also, apparently futures also has an async mutex which would eliminate the async_std dependency, but I can't find one in Tokio, so I guess if you use Tokio it's better to use tokio::join and async_std's Mutex and eliminate futures? Idk, all of these crates also offer a ton of other overlapping features, pick whichever you like. Future is the glue and it''s defined in the standard library so pretty much all of these should just work together.
  • 1
    note: if you use the futures::future::join (or join3 etc) function instead of a macro, rust-analyzer won't be disabled inside the async blocks
  • 0
    @jestdotty not true. WebAssembly on itself doesn't have access to browser API. You still need javascript as glue. It will dominate forever or something
  • 1
    @retoor there's libraries that do that glue
  • 0
    @jestdotty javascript libraries. There's no escape. But yeah, you're right. You don't have to code a line of js script or maybe two to make it happen probably.
  • 0
    @lorentz Man, hearing the @jestdotty story almost makes me agree with the people that say async rust was a mistake... It really wasn't -- and in fact I just prototyped fibers (async without await) in Rust and came to the conclusion that it's just objectively worse -- but it still makes me sad that someones first experience with Rust is async fuckery

    The language has so much else nice to give
  • 0
    @lorentz

    ok so evidently you can use Mutex without Arc

    and if you take &mut self you don't need to put it back, it seems to automatically do it
  • 1
    @12bitfloat the docs are just bad, the community is toxic and says inconsistent things and nitpicks so there's nowhere to learn. it's worse than stack overflow (stackoverflow was actually very good for other languages)

    AI always wrapped Mutex in Arc first. fuck if I know

    and I didn't know you could make an async block and not move values into it? I don't even know how that makes sense frankly
  • 2
    @retoor I don't know if they're JavaScript. there's a rust crate that just gives you all the JavaScript dom and debug tools like console.log and etc stuff but through a rust interface

    and you can write ffi for every call you want to make I guess yourself or you can just use the crate that already wrote the ffi

    but you do still need to cross that barrier and there can be issues with that sometimes. like strings are represented differently so if you pass data back and forth a lot it'll negate any assembly speed boosts you got for example. screeps community showed me this

    also sometimes wasm compiler just compiles something kind of wrong. wasm is pretty "new" still, so a bit will be off in some data type or whatever. ironically stacktraces in wasm are better than native rust
  • 1
    @jestdotty I agree with you! (somewhat)

    Doing async rust well is very complex. Normal Rust is already complex but async makes it 2 times harder

    Unfortunately there isn't really a fix for that. It isn't that Rust is bad, because Rust is insanely good. It's not that async Rust is bad, because it's probably the best async implementation possible inside Rusts framework of rules

    It's just that.... Rust is hard, and frustrating, and sometimes really annoying.

    But it's such a beautiful language I just can't hate it
  • 1
    @jestdotty To answer more directly:

    * Yes the Rust community (despite the marketing) is toxic; really just as toxic as any other online community is toxic (I just wish they would stop saying that "oh we are so non toxic crap")

    * AI for Rust sucks, but really AI just sucks for most of non-trivial programming

    * Well yeah you can have async blocks which are move (and thus 'static) or not (and thus not 'static, which can be really useful)
  • 1
    @12bitfloat I mean I'll bitch and irrationally complain but the reality is I have no business judging something until I fully understand it, and I know it

    also why criticism doesn't bother me. does the person actually know what they're talking about? no? well it's not a well informed opinion so 🤷

    in case you think my stuff is harsh 😁

    I am fully aware I am whining about my own incompetence. to me, this is humour
  • 1
    @jestdotty No, I get it :D

    When I was learning Rust I was so fucking furious I wanted to throw my computer out of the window

    I don't know, for me Rust is really something different. I still program in Java, C#, Python and JavaScript and I like all of these. They let me make something quickly. And I really like that

    But Rust also has something I really like: Despite the complexity and stuff, just the feeling of making something that's truly robust. Something that can't just break willy nilly, I really like that
  • 1
    @12bitfloat move is used when you don't know how long a lifetime reference is going to be

    async... how could you know how long the lifetime is going to be?!

    I guess you don't return the impl futures... so technically it's happy then 🤔, cuz you resolve / await them before you're done with the method

    I was passing around anonymous functions earlier and that necessitated move 😁 (that was my attempt to use a music generation library... which probably was harder to understand than async 😭), so that probably got my brain confused also. *makes excuses*
  • 1
    @12bitfloat well I like when I leave and come back for some reason I'm not confused by my code, and the speedup is really fast

    that's been a haunting feature of other languages for me

    also. who doesn't like a little pain?!

    one of the things I liked about programming is it tells you when you're wrong. rust sure does that a lot!
  • 1
    @jestdotty move is a special keyword on closures specifically that means "any values touched by this closure should be moved in, instead of being referenced"

    I'm not *that* well versed on borrow rules (to be fair, they are insanely complex lol), but normally futures should work fine

    I suspect (thought I might be very wrong) that your issue is, that you return `impl Future<Output = Foo>` and you want to use that. It might be that you need `impl Future<Output = Foo> + Send` so that you signal that it is thread safe

    Not entirely sure though, variance is such a complicated topic
  • 1
    @jestdotty Also your problem may or may not be addressed by this new language feature: https://blog.rust-lang.org/2024/10/...

    (like I said, lifetimes are complex :P )
  • 0
    @jestdotty Also funnily enough, my fiber implementation in Rust would maybe actually help you :D

    It's not implemented yet, but it doesn't require async or lifetimes and just works.... it also has pretty big downsides (big virtual stack size, less flexibility), but it's a pretty cool experiment
  • 1
    @12bitfloat I copied lorentz' thing and applied it to my demo. thought maybe because he was using u64 he was using Copy trait hence it was working and wouldn't work with something like String but I was incorrect. turns out I was doing a bunch of useless things that were unnecessary to do and they were causing me headaches

    writing my code into his' format now. should work (gotta throw it through tests and such)

    I have no idea what the link you pasted is lol

    my issue wasn't lifetimes, persay. I was messing with lifetimes when I didn't need to be!

    yeah always best to keep things simple. perhaps good hygiene learned from rust for other languages, so people say
  • 1
    @jestdotty Oh yeah, keeping things simple is always the right approach, especially in rust :D
  • 1
    @12bitfloat my older code would lag my Linux OS and then Linux would kill the process cuz it took up so much RAM lol. the rewrite uses 400 MB instead. lorentz' way of doing async in this case also omits necessity to clone, so that might even get a little better

    I don't know if it's so much an async problem persay. before this I wrote 2 of my own async implementations, and then I switched to tokio. rust async is a mess but as far as I'm aware at least it works

    I do have a weird hanging bug somewhere I can't find... AI advocated I use parking_lot crate to find deadlocks but that never found anything. could be an async is just having an error or an infinite loop somewhere? I don't know. doesn't happen that often and not mission critical for now
  • 0
    @jestdotty Good question... parking_lot's deadlock check probably didn't find anything because if it did, your pogram would have soft locked instead of just been slow :D

    Just a quick check: Are you running in release mode? (--release)
  • 1
    @12bitfloat no it's undoubtedly something I'm doing

    I'm churning through a lot of data and eventually it stops churning as fast until it just stops logging all the churning lines, aka the threads are stuck on something I guess

    and if my program finishes, sometimes there will be one record that didn't finish. which means something is getting clogged somewhere. but this is a whole giant workspace of like 12 crates so. needle in a haystack problem
  • 1
    @jestdotty kinda new but there's sick shit done in that already like a port of openttd (transport tycoon open source) and freaking autocad. Last one is quite extreme.
  • 1
    @jestdotty oh boy, that sounds fun <.<
  • 1
    @jestdotty Regarding deadlocks, are you absolutely sure that no future ever blocks the thread waiting for the result of another future, such as by receiving from a stdlib MPSC queue or locking an stdlib mutex?
  • 2
    @lorentz the multi threading is very simple, no circular dependencies
  • 1
    @jestdotty Even if simple make sure to never hold an std/parkinglot mutex guard across an await point

    It really could be a deadlock that at the start is unlikely due to a short lock duration but as you process data and fill up your data structures the critical section becomes longer and longer so the chance for a task trying to lock while another task currently has the lock goes up dramatically
  • 1
    @12bitfloat idk what await point means

    is there an example?

    yeah so umm... issue is, I have x * 500 asyncs going, and when x reaches about 100-200 then it seems like something hung. so the bug is not predictable. like 1 in 100*500=50,000 chance at best. a lot of logs to go through if I'm trying to find it that way
  • 1
    @jestdotty Await point is each point where you call .await

    The problem with holding a mutex guard across an await point is this: If one task locks the mutex then calls .await, it may now give up execution to another running task. If that second task tries to acquire the same mutex and both tasks are scheduled on the same os thread, you've now deadlocked the tread

    It happening at a later point in your program could be, like I said, because your critical sections are getting longer as time goes on, so the chance goes up
  • 0
  • 1
    looked it up just now cuz was suspecting this might be the case

    AI used to be so much better before, I swear its quality is degrading

    parking_lot only detects deadlocks for things made with its provided types. but I'm using mutex from tokio
    so no wonder it isn't telling me anything about finding a deadlock

    found a rust forum post that claims tokio doesn't have any deadlock detection (and also then them claiming you shouldn't use tokio's mutex... I don't want these arguments. it's like nobody knows anything. bad this, good this. nobody's an expert and is instead just opinionated. it's so weird. I miss nerds that over explain all caveats)

    if a lock is stuck looping trying to acquire too long, is it so hard to print a line or notify or something? why can't this be part of the crate?

    my other idea was finding a performance debugger like java had. a profiler. and in the jvm one it would tell you how long anything spent in a specific function, that way I could notice it via the profiler
  • 1
    @12bitfloat oooh I see. that's a valid point. I didn't think of that

    ok I don't think I do that anywhere though

    I just saw this guy's example: https://users.rust-lang.org/t/...
    haha. yeah that's obvious to me

    but I do have some infinite loops and I made things unwrap because otherwise I had no stacktraces and was missing errors / couldn't find errors. so it's possible something is stuck in a loop or a thread panicked and just got lost somewhere

    the infinite loops is literally because the solution to a bunch of errors advocated by crates or the REST API I'm hitting is to "try again"... but every time something tries again I log that it's trying again and how many tries it has done. granted I don't do that for everything maybe

    ... actually nevermind on the unwrap making threads get lost. I did just have the app crash because the REST response had an unanticipated json format. not sure if that call was in an async environment though...
  • 2
    ok the parsing REST error happens in an awaiting which means if you unwrap in an async block it will crash the whole app

    therefore the infinite loop cannot be caused by an unwrapped panic somewhere losing a thread because losing a thread at any time will crash the whole app. excellent. one possibility excluded as the cause of my problem
Add Comment