[–] 3 points 9 months ago* (5 children)

Python is one of the more forgiving and extremely versatile.

I highly recommend checking out the game “The Farmer Was Replaced” on Steam as it might be the best way to introduce yourself to programming concepts outside of a classroom. (Not affiliated, just love the game XD)

Then in no particular order:

  • Rust (and understand C++ and all interops)
  • Typescript
  • Bash
  • DotNet (Java that works)

And as always - learning the anti patterns is more important than learning the patterns.

  • source
  • [–] 3 points 9 months ago (6 children)

    I'm curious what you mean by the payoff being a ways away. Do you feel you don't understand some aspect of Rust well enough to write anything in it?

    As a tangent to that and your original question what languages do you already know? Understanding where your knowledge is lacking could help provide better answers as what languages someone enjoys learning/using tends to change a lot as they become more experienced and start to develop an appreciation for the more complicated problems more involved languages help solve.

  • source
  • parent
  • context
  • [–] 6 points 9 months ago

    Someone once told me somewhere, that if I am trying to learn rust, I should learn C first, so that I know how to shoot myself in the foot, learning to avoid doing so

    This is stupid advice. If you want to learn rust then learn rust.

    So thats what I did (somewhat) for the past 6 months. I wrote some stuff in C

    In that time you are no closer to learning rust. If you started with rust you would know it by now. Rust is not harder to learn then C. If anything C is harder to learn as it's compiler doesn't guide you at all.

    You don't need to learn C to appreciate the borrow checker. I find beginners just accept whatever they are first taught. It is only really those that come from C the put up a bigger fight when learning rust.

    And 6 months in a language without a borrow checker is not really long enough to learn the reasons why a borrow checker is useful. Not without a good guide that focuses on that. Which most c books don't. The best way to learn it is with rust that actually tells you when you mess up.

  • source
  • [–] 1 point 9 months ago

    Someone once told me somewhere, that if I am trying to learn rust, I should learn C first, so that I know how to shoot myself in the foot, learning to avoid doing so

    This is stupid advice. If you want to learn rust then learn rust.

    So thats what I did (somewhat) for the past 6 months. I wrote some stuff in C

    In that time you are no closer to learning rust. If you started with rust you would know it by now. Rust is not harder to learn then C. If anything C is harder to learn as it's compiler doesn't guide you at all.

    You don't need to learn C to appreciate the borrow checker. I find beginners just accept whatever they are first taught. It is only really those that come from C the put up a bigger fight when learning rust.

    And 6 months in a language without a borrow checker is not really long enough to learn the reasons why a borrow checker is useful. Not without a good guide that focuses on that. Which most c books don't. The best way to learn it is with rust that actually tells you when you mess up.

  • source
  • parent
  • context
  • [–] 7 points 9 months ago* (1 child)

    The fact that people treat Rust like it's very difficult is odd to me. I write Rust because C was too hard. Lol.

    I tried to learn C, but once the learning materials got into double pointers and void pointers, I stopped being able to follow it. So I went back to Rust and after about a month of practice, I no longer struggle with the borrow checking rules (usually the hardest thing for people new to Rust) and it just keeps getting easier over time.

    If you know C, you're probably more than well prepared for Rust.

  • source
  • [–] 5 points 9 months ago

    if I am trying to learn rust, I should learn C first

    Bullshit. I learned C++ instead of C and I don't regret it. One step further and you should learn assembly, or the electronics powering the computer. Learn whatever you want.

  • source
  • [–] 1 point 9 months ago

    I have written a custom synthesizer for my game engine, with the audio running on its own thread. In this case, I managed to get away without any audible issues.

    Same with my evdev event readers, that required their own threads, or else they blocked all other threads. No mutexes.

    Your mileage may vary though, and probably with extensive testing I could find hazard cases.

  • source
  • [–] [S] 1 point 9 months ago

    For anyone interested, I did make a second version of the same logic. Even if i kind of had atomic operations in mind i did not know that i was thinking of atomic or what atomic was for that matter. So in a broad sense i assumed raw pointers were atomic. Also worth noting implementing a false Sync for &str seemed to be unnecessary to get it to run in the first example even if i got the impression during construction that it was. Just pretend in the first example "ExemptSyncStringSlice" is just &str if you want to compare them for some reason.

    I don't know the overhead of AtomicPtr compared to raw pointers and it is dependent on operating systems that can use an atomic load store (whatever that means.) But this version seems more "correct" at least.

    use std::sync::atomic::{AtomicPtr, Ordering};
    use std::time::Duration;
    
    
    fn main()
    {
    	let pointer: AtomicPtr<&'static str> = AtomicPtr::new(&mut "Hello!");
    
    	let mut value2: &'static str = "Hi!"; // Place outside scope due to lifetime.
    
    	thread::scope(|scope|
    	{
    		scope.spawn
    		(|| {
    			for _ in 1..1000
    			{
    				unsafe { println!("String = {}",  *pointer.load(Ordering::Relaxed)); }
    			}
    		});
    
    		scope.spawn
    		(|| {
    			sleep(Duration::from_millis(1));
    			pointer.store(&mut value2, Ordering::Relaxed)
    		});
    	});
    }
    

    Thank you all who responded btw.

  • source
  • [–] 1 point 9 months ago

    I would expect unsynchronized access to the same memory to be Undefined Behaviour (and I checked that in C++ it is: https://stackoverflow.com/a/79698067/1122720 and then I also checked that in Rust it also is: https://doc.rust-lang.org/reference/behavior-considered-undefined.html)

    Considering that, I wouldn't expect coherent results. In simple cases the compiler may optimise away a lot of code based on the assumption that UB never happens, see also: https://predr.ag/blog/falsehoods-programmers-believe-about-undefined-behavior/

  • source
  • [–] 2 points 9 months ago* (last edited 9 months ago)

    Hehe, me too. I love microcontroller programming. That kind of forces you (at times) to think about the low-level stuff. And maybe have a look at the CPU datasheet once you go deep down. Something like an ESP32 or RP2040 has 2 CPU cores. And it's way easier to tell what happens compared to a computer with a complicated operating system in between, and an x86-64 CPU that's massively complicated and more or less just pretends to execute your machine instructions, but in reality it does all kinds of arcane magic to subdivide them, reorder things and optimize.

    (Edit: And with C++ you get to learn all the dirty stuff... How it sometimes initializes variables to zero, sometimes it doesn't... It's your job to address memory correctly... Maybe one day I'll learn Rust instead of all the peculiarities of C++ 😆 And Rust support on microcontrollers is coming along, these days.)

  • source
  • parent
  • context
  • [–] 4 points 9 months ago

    Whether something's atomic or not depends on the language you use -- and if the language was vague about it (like old C) then also how the CPU works.

    At the CPU instruction level, there are other factors like how an instruction interacts with memory. Go look up CMPXCHG (from x86) for example, if you want to go down the rabbit hole. There's a StackOverflow answer here that you might find interesting about using that instruction in combination with the LOCK prefix.

    At the language level, there are usually either guarantees (or a lack of guarantees...) about what is safe to do. C++11 (and later) have std::atomic for defining variables that are accessible from multiple threads safely without manually using a mutex, for example. You generally cannot assume that writing to a variable will be safe between threads otherwise (even if you think the operation should compile to a single CPU instruction) without using a supported concurrency mechanism that the compiler knows how to deal with. Consider the case where the compiler chooses to store a value in a register during a loop as an optimization and only write the value back to RAM at the end of the loop -- while that value is changed in RAM by another thread! If you use an atomic variable or protect access with a mutex, then the program will behave coherently. If not, you can end up with inconsistent state between threads and then who the fuck knows what will happen. This SA answer might also be interesting to you.

    In Python (specifically the cpython implementation), there's the Global Interpreter Lock (GIL). Some things are safe to do there in that language implementation that aren't safe to do in C because of the GIL. (You still generally shouldn't depend on them though since people are trying to remove the GIL to get better performance out of Python...) Basically, cpython guarantees that only one thread can run Python byte code at a time so interactions are serialized at that level even if the OS swaps threads in the middle of cpython computing the behavior of an instruction.

    Hope that helps a bit.

  • source
  • parent
  • context
  • [–] [S] 3 points 9 months ago (1 child)

    Well worst case to come with language design i could always learn assembly ;) Half joking but thank you very much for your answer. As for the example the only reason its rust is i figured it would be the easiest language to get the logic right even if i have more hours in C++ technically. Arrays seemed obvious enough that would break but i was unsure about things like pointers and integers. Just find the "lower" levels kinda fun ngl.

  • source
  • parent
  • context
  • view more: ‹ prev next ›