• 0 Posts
  • 37 Comments
Joined 1 year ago
cake
Cake day: July 9th, 2023

help-circle

  • Classes are Data plus the code required to modify that Data. The idea is to encapsulate data modifications into one thing (a Class) that knows how to modify all the Data as a single unit. This lets us write some code to describe, say, a Scrollbar widget. The Class for the widget combines all the Data for a Scrollbar (position, orientation, bar size, total size, etc) with the methods that read or modify that data (scroll up/down, change size, draw, etc).

    That’s the first Big Idea of OOP - that data should be grouped with the functions that modify it. If you don’t have that - as in C - you have to write functions that only work on a given data type but which are namespaced separately. You get functions like void set_scrollbar_pos(void* scrollbar, word pos) which become verbose in a large project. (I’m not saying this is the worst thing in the world, just a different style.)

    The second Big Idea of OOP is message passing. Now that we have code and Data bundled together, it would be nice if Objects that share functions of the same essential type and intention could be swapped out interchangeably. So instead of directly invoking a function on an Object, we send a ‘message’ that says something like ‘if you know how, please draw yourself on screen, relative to X,Y’.

    Of course, since plain English is hella verbose, the actual message is going be something like “draw, X,Y” and the Object receiving the message then sorts out if it has a method called “draw” that can use the provided X and Y. If so, it runs the code to do so. If not, you get an error.

    Messages like this mean that you can swap out compatible Classes for one another. E.g. you can ask any collection of widgets to .draw themselves with a single method and let the compiler/interpreter generate the machine code as needed. That reduces the amount of boilerplate for engineers by a lot! Otherwise, trying to work with any collection of heterogeneous Objects (like a List of every Widget contained in a Window) would need to have essentially the same code rewritten for every different Type needed - a combinatorial explosion of code!

    Tl;Dr -

    • Classes help organize code and simplify state management by combining data with the functions that manipulate that data.

    • Classes reduce the amount of boilerplate code needed by allowing methods with the same “shape” to be called interchangeably.

    Everything else about OOP is essentially built off these two ideas. I hope that helps.




  • glibc is the library that provides basic functionality for C programs. It provides the bottom level implementation for things like opening files, requesting memory, and other OS-level stuff.

    glibc isn’t the only implementation out there. Even on Linux, there are other options, such as muslc.

    It gets updated regularly, as the C standard or operating system needs. So while it has been around for a very long time (by software standards anyway) it’s still an active and evolving piece of software. --and one that underpins many critical functions of our systems.


  • Once upon a time, I built a proof of concept distributed social network that ran entirely on cell phones.

    I eventually ran into enough complications that I abandoned the project. But the tech did work. I could create posts, add friends, etc. (It just wasn’t reliable in its sync mechanism and I gave up trying to fix it.)

    So… Imagine Lemmy, but a community’s data is stored collaboratively on mobile devices, the load shared by all its subscribers.

    We all walk around with goddamn supercomputers in our pockets. We should put them to work.



  • Generally, some algorithms are more easily expressed as recursive functions than iterative loops. …and vice versa. And realistically, that’s how you should choose ninety nine percent of the time.

    But if you want to get into the weeds… Prefer iteration unless you know one or more of the following:

    • Your maximum iteration depth is bounded and cannot overflow your machine’s stack depth.
    • Your algorithm can be implemented with tail-call recursion AND your language supports the same.
    • Your senior/team lead wants a recursive solution.

    Because in environments where none of the above are true, iterative solutions are usually more performant, safer, and better understood.


  • Programming success is more closely associated with language skills than math skills.

    Yes, if you need to invent a new algorithm you’ll need math. Computer Science is definitely mathematics heavy.

    But writing a program is all about expressing your intent in a programming language, step by step. It’s about “communicating” with the machine (and your users).

    All this to say, I got C- and D grades in my math courses in college and still became a successful computer programmer. I’m not pushing the boundaries of computation, but if you need an app for your business, I can build that for you in a reliable, tested, and flexible manner.

    Edit: Also! I love Common LISP. It’s such an amazing language and I’m so sad that it isn’t more popular in the industry.






  • Aw man, you can’t write all that and then not give an example!

    Ruby makes scripting drop-dead simple. You can run any shell command by surrounding it with back ticks.

    # simple example, just grab files: 
    files = `ls`.split("\n")
    
    # pipes work inside back ticks
    files.map {|f| `cat #{f} | grep "can I use grep w/out cat"`}
      .compact
      .each { |match| puts match }
    # easy to build a pipeline on the data in ruby, too! 
    

    That’s it! No messing around with popen3, or figuring out pipes or signals. Those are there too if you really need them, but if you just wanna write a quick script with a less arcane syntax - try Ruby!


  • I loved (and still do) the rush of solving the puzzle. Programming languages give you a constrained set of rules to express yourself with. And yet we know that you can create literally anything with those rules if you can just put them together in the right way.

    I love when a program actually comes together and it works for the first time! When I’ve started from nothing but a vague desire and then pulled a solution from out of the void. It’s as close to actual magic as anything else I can think of.

    I compel lightning and stone to my will, commanding them in unspoken tongues.




  • I can live with the forced indent in Python, but I really prefer Ruby’s “fluent” OO style vs Python’s more functional style.

    e.g. I prefer seeing operations in processing order like

    get_all_foos()
      .map{|foo| foo.id}
      .each {|id| report("found foo #{id}"}
    

    vs Python’s functional order

    [report(f"found foo {fid}") for fid in map(lambda x: x.foo_id, get_all_foos())]
    

    (Also, Python claiming useful variable names like type and id deeply annoys me)


  • I get that. Ruby does do a lot under the hood for me. But I like that! Different Strokes and all that.

    I guess, for general programming tasks, I enjoy when the language is “clever” enough to do The Right Thing for all the bits I don’t really care about in the moment (like memory management) so I can focus on the logic that solves my problem.

    Otoh, my last “big” personal project was a terminal multiplexer (and some supporting TUI widgets) that needed to run on a raspi zero W. I started in Python, then moved to Kotlin and finally Rust in the pursuit of performance. Once one of the parts I needed to care about became efficient performance, moving to a lower-level compiled language was the move.

    Indeed, one app in particular took 1.5 min to run in Python…which ultimately dropped to 3 sec in Rust - and that was mostly network latency!

    I love languages of all sorts. I’m currently writing an interpreter for a language I’m designing for fun. I’m starting off in Ruby while I figure this all out. I fully expect performance to be appalling. But Ruby lets me build faster while I’m testing things out and learning how interpreters work.

    Once I’ve got my interpreter working though, I’m planning to port it to Rust for better performance.