Programming thread

How is this any different from just transferring the text file to the client? Are you storing this data locally for some reason instead of downloading it? If you are storing it, why are you not just using a DBMS or document storage system to manage this data? I understand wanting to do C stuff at a low level, but maybe stay in your lane as a beginner and use working storage solutions like mongodb and SQLlite or H2.
I should have clarified by turning the text into a bunch of numbers you can make it much smaller, from 100mb to (hopefully) 100kb max, when you send it to someone else so it doesn't take something like 5 minutes to download and only takes a couple seconds. It is that slow because the host has to upload it which is slow and some people tend to have slow internet.

You are probably right that there are things that could do this much easier and it isn't the easiest project to do, but it is something I would find interesting and useful, which will keep me going if I hit roadblocks.

Even if I fail and only get like 60% of the way to being finished I count that as a win because I'll be much more familiar with C.
... So, compression?
Yes basically although I'll take advantage of the fact that the skeleton of every file is the same and only the numbers change.

Compression has been used on these files before but it can take a while (relatively speaking) and it only reduces file size by at most 10x.

I'd like to see if I could get it to be much smaller. If I fail that's alright I'll still learn a lot in the process.
 
Thoughts, questions, and suggestions? This is your opportunity to wax poetically or wax autistically about any detail of this project I'd like to work on.
Use rsync

This again, is totally worth the tradeoff and streamlines deployment.
This is what bothers me about Rust shills. They never say "this bit is a bit shit, this was a design mistake", like users of other programming languages do - everything is the bees' knees all the time.

Static linking is dumb, and the only reason Rust does it is to avoid deciding on a stable ABI. So instead of recompiling all your packages every time there's an ABI break, or every time the compiler version changes, you do it for every project. This is not an improvement. It's only the fact that there's no huge libraries like Qt written in Rust that this has been tolerated so far.
And, of course, it doesn't play nicely with distro package managers, which pisses everybody off.

And you can't ignore how pozzed the community is, because sooner or later you will have to interact with them. Even if it's just reading the stuff that uwu_lillith (she/her) has posted on StackOverflow.
 
Patrick S. Ferrlinson: "No, C child. It's not an unstable ABI, it's a RICH TYPE SYSTEM. Who would even use dynamic linking anyway? It's 2024 and we have infinite disk space so we can store 30 different copies of the same library."

It's like C++ but more C++ in every way possible, the very epitome of niggerlicious template bullshit that results in 126MiB binary images. And even C++ can do dynamic libraries.
 
Just a tip @SandyHooker , When youre working with JS programs like that where nothing visual matters, you could use Node instead to execute your JS code in the terminal. That way you will not have to bother with HTML boilerplate code and you will get used to the terminal as well as introducing yourself to node.

Getting aquainted with the terminal, even just a bit, will make you a stronger candidate as a new dev, and being comfy in the terminal helps with anything programming/IT.
 
I play or at least used to play a lot of Grand Strategy games by Paradox. One issue that comes up when you are playing multiplayer is rehosting where you have to transfer the save game to every person in the multiplayer lobby. This can sometimes take upwards of a minute or even longer as these save games can get up to 10 megabytes or 100 megabytes sometimes even close to a gigabyte if it is a big game and it has gone on for a long time. When this happens it means the process of rehosting can take 5-10 minutes especially if someone's connection is a bit slower.

These save game files are essentially just scripting files stored as a text file with variables written out with something like "{London craftsmen = 300123 }" to represent there being 300123 craftsmen in London but for every single entity in the game.

However these save games are essentially just text and they are the same every time meaning I can make something that parses this save game text file and then stores all that information extremely simply and then transfers it where it gets reverse parsed into the save game text file.
String handling? In C? My big personal C project has several times more code handling strings than it does on doing what it's supposed to do (Some of this is my own desire to avoid NIH stuff, I'm well-aware, whatever. It does what I want.), and all that code does is handle command-line arguments and resolve filenames. This is a much, much bigger project than you think. Handling strings is one of C's biggest weaknesses. Whenever I see a project that involves string mangling, I default to Ruby.

Other folk said "use rsync" and "so this is compression" and they're saying this for a reason. You're not going to do any better than sending a ZIP-file, much less picking something a bit more esoteric (LZMA, 7Z, XZ) for a couple percent improvement. "This is a simple text file that I can parse easily" is a hill that I've seen many, many very intelligent and well-meaning individuals break themselves on.

So, I'll echo what they said. Use "rsync -z". That way, you get rsync behaviour and baked in compression without effort.
 
I withdraw my earlier statement. If you know the order of the fields, you could open up a socket on the host/client and only send the numbers without the field names via UDP packets in the correct order. Then just reassemble the packets into a file when you've got the last number packet. Pro tip smaller packets mean faster transfers, so you may want to split the packets to only have one value for packet. You'll only see these performance gains if you use UDP though. TCP is a Jewish trick pushed by Google Cloud and AWS to up bandwidth so they can bilk enterprise clients out of every cent they can.
 
Last edited:
And you can't ignore how pozzed the community is, because sooner or later you will have to interact with them.
And for those working in Corporate America, imagine having to hire a Rust developer. It'd be like playing Russian roulette with HR disasters, especially if the suits want a "credentialed lead engineer" or whatever.
 
I should have clarified by turning the text into a bunch of numbers you can make it much smaller, from 100mb to (hopefully) 100kb max, when you send it to someone else so it doesn't take something like 5 minutes to download and only takes a couple seconds. It is that slow because the host has to upload it which is slow and some people tend to have slow internet.
A point of caution: network interfaces will almost always use compression by default. If all you were doing is compressing the file, you probably wouldn't see much if any performance increase.

You've got to do more than just compress the data, you've got to find a way to actually eliminate some of it, and then re-create it at the other end. Something like @macrodegenerate suggested, where instead of an object containing key/data pairs, you simply omit the keys and put the data into a fixed order. The receiving end can decode this if it already knows what the keys are and it knows the fixed order that you used.
 
Just a tip @SandyHooker , When youre working with JS programs like that where nothing visual matters, you could use Node instead to execute your JS code in the terminal. That way you will not have to bother with HTML boilerplate code and you will get used to the terminal as well as introducing yourself to node.

Getting aquainted with the terminal, even just a bit, will make you a stronger candidate as a new dev, and being comfy in the terminal helps with anything programming/IT.

I'll definitely look into that.

The project I was doing was a free code camp thing that I had to do html to complete. I was finishing up the projects on there and I plan on looking through some other sites I found to build on my knowledge.

I've worked with nodejs a bit cause I've made a few applications in electron for practice. I was way over my head at one point, but now something that would have taken me a week to figure out only takes me a couple days at most. I have so much to learn its genuinely intimidating sometimes.

My imposter syndrome is telling me I should be way ahead of where I am at but hey I am doing good for a brain damaged tard who went into this stuff completely blind.

Btw, Here is a roman numeral converter function. Goes up to 3999, Its pretty niggerlicious, but I'm glad I'm getting better at this stuff.

Maybe someday I'll make a website called Pitbull farms.

JavaScript:
function validate(){
    if(input.value == 0){
    output.innerText = "Please enter a valid number";
  } else if(input.value < 0){
    output.innerText = "Please enter a number greater than or equal to 1";
  } else if (input.value > 3999){
    return output.innerText = "Please enter a number less than or equal to 3999";
  } else {
    convert();
    }
};


function convert(){
  output.innerText = '';
  let value = input.value;
  while(value.length < 4){
    value = "0" + value;
  }
  console.log(value)
  //Thousands
  for(let i = 0; i < value[0]; i++){
    output.innerText += 'M';
  }
  //Hundreds
  if(value[1] == '9'){
    output.innerText += "CM"
  } else if(value[1] >= "5"){
    output.innerText += "D";
    for(let i = 0; i < (value[1] - 5); i++){
      output.innerText += "C";
    }
  } else if(value[1] == "4"){
    output.innerText += "CD"
  } else {
      for(let i = 0; i < value[1]; i++){
    output.innerText += "C";
    }
  }
  //Tens
    if(value[2] == '9'){
    output.innerText += "XC"
  } else if(value[2] >= "5"){
    output.innerText += "L";
    for(let i = 0; i < (value[2] - 5); i++){
      output.innerText += "X";
    }
  } else if(value[2] == "4"){
    output.innerText += "XL"
  } else {
      for(let i = 0; i < value[2]; i++){
    output.innerText += "X";
    }
  }
  //Ones
     if(value[3] == '9'){
    output.innerText += "IX"
  } else if(value[3] >= "5"){
    output.innerText += "V";
    for(let i = 0; i < (value[3] - 5); i++){
      output.innerText += "I";
    }
  } else if(value[3] == "4"){
    output.innerText += "IV"
  } else {
      for(let i = 0; i < value[3]; i++){
    output.innerText += "I";
    }
  }
}
 
  • Like
Reactions: y a t s
@SandyHooker
Dont worry about impostor syndrome, m8, everybody feels it, programming is a vast thing, and there is always more to learn.

Imho if you can build things like that all you need to do is to keep building stuff and you learn stuff along the way.

As for your code, congrats, its not the simplest program to make, here is just a couple of aspergers pointers which might not always be so apparent to new people (and also does not matter a whole lot here but its a chance to learn):

1.
In your for loops conditions which are like i < (value[1] - 5); the program would perform better if you, before the for loop, make a variable of (value[1] - 5) and check if i is less than that. The reason is that in its current state the for-loop has to calculate (value[1] - 5) every iteration of the for-loop. It probably does not matter much at all here since 3999 is the max input value, but it does start mattering when you have to iterate tons of times so its good to know about and good praxis.

2.
It would also be more performant to not append new characters to innerText all the time, but make a variable, append to it, then set innerText to it once at the end of the function. Reason being that you are constantly calling the property of a DOM element which usually is a taxing manoeuvre so its good to limit it when you can.


These are probably autistic considerations at this time in your JS-journey but important once your skills and programs grow. If you ever want to see how long something takes to execute, use console.time() before the code you wish to test, then console.timeEnd() after it.
 
This is what bothers me about Rust shills. They never say "this bit is a bit shit, this was a design mistake", like users of other programming languages do - everything is the bees' knees all the time.
It is genuinely that good when compared to things like C and C++ as well as all of those nu-C languages like zig. The only thing I can think of that suck are first-time builds from scratch, which are slow, but that's more of an LLVM thing than a rust thing. Once you complete your initial build, incremental builds are usually under a second. Also it would be nice for them to settle on a stable ABI for rust so that things like the standard library can be offloaded.
They don't want you to use genuinely good things, they want to keep them for themselves.
Static linking is dumb, and the only reason Rust does it is to avoid deciding on a stable ABI
Static linking is good for many reasons, two of the best reasons I have previously explained.
And you can't ignore how pozzed the community is, because sooner or later you will have to interact with them. Even if it's just reading the stuff that uwu_lillith (she/her) has posted on StackOverflow.
Works for me. All the tranny shit disappears when you stop looking for it. They'll be dead and gone soon anyways.

No, C child. It's not an unstable ABI, it's a RICH TYPE SYSTEM. Who would even use dynamic linking anyway? It's 2024 and we have infinite disk space so we can store 30 different copies of the same library
The type system is unparalleled, you don't know this until you have tried it, and really is sublime, the things you can model purely with declarative types is insane.
Copies of the same library is reasonable on a developer machine and it has been this way for at least two decades. This is not reasonable on a consumer machine unless there is no barrier to install and it happens automatically, like how steam handles common redistributables. You can't expect someone downloading your thing to also have to install version xyz of libnigger so that their loader can load ABI compatible libnigger-2.4.3.so instead of the version libnigger-2.5.3.so that they already have on their computer. That's on you, the developer. It is much better for distribution if you just statically link libnigger version whateverthefuck you need with your binary.
The other option to solve this problem is to package your program in some shitty container like snap, flatpack or appimg so that you can include the versions you need, but this is just static linking with extra steps. You could also try and target a single distribution where you can expect certain versions of things to be installed or provided by the package manager, but then what about cross platform? are you really going to produce N builds where for every build you have to ship N platform specific dynamic library versions, and then across multiple architectures too? I doubt it.
You could also try and mandate all your users to use the version you want them to, which is either a big enough barrier to have them disregard your thing, or have to live with multiple versions of the same library on their system, which is what was going to happen anyways in all but the theoretical best case scenario where everyone happily agrees on library versions and everybody updates to the new version at the same time, which is basically limited to single linux distributions.
There's no best-case here, it's a series of tradeoffs that you have to make based on what you want to prioritize, and rust made the best tradeoffs all things considered, while keeping the other options viable for those that really want them.
the very epitome of niggerlicious template bullshit that results in 126MiB binary images
Generics + strong typing basically mandate the use of monomorphic copies of functions for each type that they are used for to retain type safety. You do this in C too but it is done manually for every primitive, int size and pointer type you need it for, and it is a hackjob in C. Templates in C++ are just preprocessor macros but they are part of the scanning and parsing step rather than a completely disconnected pre-processing step, they are marginally better than C preprocessor at the expense of syntactic aesthetics, which is a good tradeoff for large gains in maintainability. C++, C and rust projects when you take into account all the things, are similarly sized. The reason your C binaries are small is because you dynamic link to libc and other libraries. Again, you take a sufficiently complex project and compare all the things, you'll find out that everything adds up to similar amounts of compiled code. The difference is how that code is stored, shipped and loaded.
 
"Static linking just wastes disk."
And RAM, and cache.
But please continue, the company I work for from time to time sells hardware, the more RAM and CPU Cache you use, the more they can sell.

Also, make sure your containers and VMs never use the same base image or libraries, this way KSM also won't help.
 
"Static linking just wastes disk."
And RAM, and cache.
But please continue, the company I work for from time to time sells hardware, the more RAM and CPU Cache you use, the more they can sell.

Also, make sure your containers and VMs never use the same base image or libraries, this way KSM also won't help.
The only real gains you get by dynamic linking are in RAM for things like very stable libraries like libc, where the OS can share the same instance across multiple processes using copy-on-write shared memory, but this is only the case for libraries that basically never change their ABI and only works if every program is compiled against it, so basically only libc and some corelibs that were going to be loaded anyways. Static linking is cope regarding CPU cache and disk space, if anything you will see slightly better cache peformance due to code all being locally, staticaly addressable rather than having to traverse an offset table to get to your position independent dynamic library that will be a 100% cache miss every time you do it.
 
Btw, Here is a roman numeral converter function. Goes up to 3999, Its pretty niggerlicious, but I'm glad I'm getting better at this stuff.
Not bad for someone just starting out :)

When you mentioned it in chat yesterday, I figured you were converting them in the opposite direction (e.g. "X" -> 10). It seemed like a fun little challenge, so I wrote a quick and dirty python thingy that does it:
Python:
rom = {
    "M": 1000,
    "D": 500,
    "C": 100,
    "L": 50,
    "X": 10,
    "V": 5,
    "I": 1
}

def conv(rn: str):
    if len(rn) == 0:
        return 0

    def rconv(rn: str, s: int):
        if len(rn) == 1:
            return s + rom[rn[0]]

        if rom[rn[1]] <= rom[rn[0]]:
            return rconv(rn[1:], s + rom[rn[0]])

        return rconv(rn[1:], s - rom[rn[0]])

    return rconv(rn, 0)

print(conv("MCMLXXXIV")) # 1984

I didn't take the time to write it very prettily or validate the numeral string, but it's compact and it works otherwise. I figured I'd put it up here to show an application of recursion.
 
  • Like
Reactions: ${Sandy}
If you ever want to see how long something takes to execute, use console.time() before the code you wish to test, then console.timeEnd() after it.
Short-running functions can be tested more accurately (and optimized) by executing them a few million times and measuring the time the whole loop takes. Divide by the number of executions and you have a better reading.
 
Yeah very good point, especially with JS the different browser engines optimize in different ways and at different times so one should loop any short code a 100k to a million times to get an accurate idea of what is slower/faster than something else
 
@SandyHooker
Dont worry about impostor syndrome, m8, everybody feels it, programming is a vast thing, and there is always more to learn.

Imho if you can build things like that all you need to do is to keep building stuff and you learn stuff along the way.

As for your code, congrats, its not the simplest program to make, here is just a couple of aspergers pointers which might not always be so apparent to new people (and also does not matter a whole lot here but its a chance to learn):

1.
In your for loops conditions which are like i < (value[1] - 5); the program would perform better if you, before the for loop, make a variable of (value[1] - 5) and check if i is less than that. The reason is that in its current state the for-loop has to calculate (value[1] - 5) every iteration of the for-loop. It probably does not matter much at all here since 3999 is the max input value, but it does start mattering when you have to iterate tons of times so its good to know about and good praxis.

2.
It would also be more performant to not append new characters to innerText all the time, but make a variable, append to it, then set innerText to it once at the end of the function. Reason being that you are constantly calling the property of a DOM element which usually is a taxing manoeuvre so its good to limit it when you can.


These are probably autistic considerations at this time in your JS-journey but important once your skills and programs grow. If you ever want to see how long something takes to execute, use console.time() before the code you wish to test, then console.timeEnd() after it.

That is all pretty helpful. It probably wouldn't make a huge difference on the short little projects I'm doing now, but if I am working on something like a backend for a website I would definitely need to take performance into consideration, so I can try making it a habit now while the stuff I am working on is relatively simple.
 
  • Like
Reactions: Benzo Samurai
Yeah very good point, especially with JS the different browser engines optimize in different ways and at different times so one should loop any short code a 100k to a million times to get an accurate idea of what is slower/faster than something else
Even if you're writing in a systems language like C various things like the OS's scheduler and malloc() (my beloved) will eat up hard-to-predict amounts of time. On JIT engines like browser JS engines it might be smart to make the loop into a function and execute it once without timing before the test proper.
 
  • Informative
Reactions: Benzo Samurai
And for those working in Corporate America, imagine having to hire a Rust developer. It'd be like playing Russian roulette with HR disasters, especially if the suits want a "credentialed lead engineer" or whatever.
Man, I should learn Rust and sell myself as a Rust dev who's also just a normal person. Finally I found my niche
 
Back