Due to potential new direction of D, I’m looking for some escape route just in case. I’m primarily a gamedev, so no functional programming languages like Rust or Haskell. Also one of the features I dislike the most in C/C++ is the super slow and super obsolete precompiler with its header files, so no zig, I don’t want to open two files for editing the same class/struct. Memory safety is nice to have, but not a requirement, at worst case scenario I’ll just create struct SafeArray<Type>. Also I need optional OOP features instead of reinventing OOP with all kinds of hacks many do when I would need it.

Yes I know about OpenD, and could be a candidate for such things, just looking into alternatives.

    • Ephera@lemmy.ml
      link
      fedilink
      arrow-up
      27
      arrow-down
      1
      ·
      3 months ago

      Yeah, it’s got some features typically found in functional languages, like first-class functions (being able to pass around functions like values) and various list functions, e.g. .map(), .filter() etc., but the basic control flow is very much imperative.

        • SorteKanin@feddit.dk
          link
          fedilink
          arrow-up
          0
          arrow-down
          1
          ·
          3 months ago

          I wouldn’t even call that a functional feature, that’s just the language being based on expressions and bool having a then method. It’s more object-oriented in that sense if anything tbh

        • Ephera@lemmy.ml
          link
          fedilink
          arrow-up
          44
          arrow-down
          1
          ·
          3 months ago

          Right. 😅

          Apparently, we’re on different pages in this regard, but to me these are less functional language features and more just modern language features.

          In my not-so-humble opinion, it was never a good idea to make everything mutable by default. It adds so much mental overhead to try to keep track of where your state could be getting modified, especially in multi-threaded scenarios.
          We just didn’t have the type system expertise and compiler technology to enforce it without runtime overhead. Now that we have that, I don’t think any full-fledged programming language should be released with everything mutable by default.

          • ZILtoid1991@lemmy.worldOP
            link
            fedilink
            arrow-up
            2
            arrow-down
            11
            ·
            3 months ago

            I only had a bug once from unintended data mutation. In a GUI setting nonetheless, where state mutability is a must. The fix and tracking down the bug took 2-3 hours at max. No thanks, I’ll be staying with datastruct.nextState() rather than const nextState = prevState.nextState() (which is even harder to from the inside), or even worse, passing around global states in a function argument at an attempt of having a program state, which is essential for gaming. You know, games are famous for having interactibility, and not just about walking around in a static world (which is allegedly a thing for the few Rust games).

            • calcopiritus@lemmy.world
              link
              fedilink
              arrow-up
              18
              ·
              3 months ago

              You can just. Have datastruct be mutable if you want. Immutable by default doesn’t mean you can’t make variables mutable.

            • Ephera@lemmy.ml
              link
              fedilink
              arrow-up
              8
              arrow-down
              1
              ·
              edit-2
              3 months ago

              How many bugs you encounter is unfortunately not a good metric, because devs will compensate by just thinking harder. The goal is rather to not need to think as hard, which increases productivity and helps out your team members (including your future self).

              It took me a few months of working in an immutable-by-default language before I had the epiphany that everything is exactly like it’s written down in code (so long as it’s not marked as mutable). I don’t need to look at each variable and think about whether it might get changed somewhere down the line. A whole section of my brain just switched off that day.

              As the other person said, there’s also nothing stopping you from using mutability, it’s just not the default, because most variables simply don’t get mutated, even in C code.
              But I would even go so far that Rust is actually making mutability fashionable again. It has introduced various new concepts in this regard, which you won’t know from other languages.

              For example, you can opt a variable into mutability, make your changes and then opt out of it again.
              And if a function wants to modify one of its parameters, you have to explicitly pass a mutable reference, which is visible both in the function signature and where you’re calling the function.

              But perhaps most importantly, it blocks you from mutating variables that you’ve passed into a different thread (unless you wrap the value in a mutex or similar).
              In most of the immutable languages up until this point, the immutability was achieved by always copying memory when you want to change it, which is insanely inefficient. Rust doesn’t need this, by instead requiring that you follow its ownership/borrowing rules.

              Edit:
              I also don’t know what you heard, but this is for example written in Rust: https://bevyengine.org/examples/3d-rendering/bloom-3d/
              The code is right below. It uses lots of mutability…

  • solrize@lemmy.world
    link
    fedilink
    arrow-up
    24
    ·
    edit-2
    3 months ago

    primarily a gamedev, so no functional programming languages like Rust or Haskell.

    Talk to Tim Sweeney.

    The Next Mainstream Programming Language: A Game Developer’s Perspective (pdf).

    Note that C++ is getting modules, that might speed up compilation, though it’s still C++ afterwards. The cool kids in systems programming are using Rust now. I have no idea if game devs are using it. Anyway, on games projects or anything else, you have to use what the other people on your team are using, which these days is still mostly C++ afaict.

    • Ephera@lemmy.ml
      link
      fedilink
      arrow-up
      12
      ·
      3 months ago

      The cool kids in systems programming are using Rust now. I have no idea if game devs are using it.

      It’s not fully there yet for production use, but there is certainly interest:

      • There’s Rust bindings for scripting Godot.
      • A game engine is being built in pure Rust, called Bevy. It’s still lacking e.g. a GUI editor, but people are already building smaller games with it.
      • And there’s a somewhat more established gamedev studio, Embark Studios, which is contributing quite a bit to the Rust gamedev ecosystem. Might know them from the title ‘The Finals’, which however wasn’t yet implemented in Rust.

      One thing to note about Rust for gamedev is that it enforces correctness to a degree which makes it cumbersome for prototyping.
      Using it with an ECS already alleviates a lot of that pain (by sidestepping Rust’s memory management). And I do imagine, much like in C++, that more and more abstractions will be built on top of it to eventually make it very nice to use.
      But yeah, Rust isn’t as clear-cut of an upgrade yet, as it is in some other fields.

        • Ephera@lemmy.ml
          link
          fedilink
          arrow-up
          4
          ·
          edit-2
          3 months ago

          It’s the “Entity-Component-System architecture”, consisting out of:

          • entities, which are basically just IDs to associate different components,
          • components, which are individual data points like the health or the position or the velocity of an entity, and
          • systems, which operate on components to introduce interactivity. For example, you might have a system which looks at all entities with a position and a velocity component, and then it just adds the velocity to the position. Then another system checks for collisions based on the position component and the dimensions component, and then subtracts from the health component when a collision happened.

          It’s kind of a competing strategy to OOP. It offers better performance and better flexibility, at the cost of being somewhat more abstract and maybe not quite as intuitive. But yeah, those former two advantages make it very popular for simulations / gamedev. Any major game engine has an ECS architecture under the hood, or at least something similar to it.

      • calcopiritus@lemmy.world
        link
        fedilink
        arrow-up
        3
        ·
        3 months ago

        Using “clever” ways to disable the borrow checker is one of the few things I don’t like about rust. I much rather it having a “borrow checker version” and a “garbage collector version”. That way we could rapidly iterate through design choices with the GC, and once the design has proven good, apply lifetimes and such to use with the borrow checker. The only downside to this I can think of is that most would just leave it in the GC version and not bother to move to borrow checker. But that’s fine by me, rust has many other features to take advantage of. As long as no GC libraries are allowed in crates.io, it should be fine.

        • Ephera@lemmy.ml
          link
          fedilink
          arrow-up
          3
          ·
          3 months ago

          Yeah, I don’t think that can happen without splitting the whole ecosystem in half. Garbage collection requires a runtime, and tons of the code semantics are also just different between the two, particularly with asynchronous code.

          I also imagine that many people wouldn’t just leave their particular program in the GC version, but never even bother to learn the ownership/borrowing semantics, even though those largely stop being painful after a few months.

          But yeah, I actually don’t think it’s too bad to have individual parts of the ecosystem using their own memory management strategies.
          The two examples that I can think of are ECS for gamedev and signals/reactivity for UI frameworks. Which is what is used in C++ or JavaScript, Kotlin, too. You’d probably still want to use these strategies, even if you’ve got garbage collection available…

          • calcopiritus@lemmy.world
            link
            fedilink
            arrow-up
            2
            ·
            edit-2
            3 months ago

            I’ve re-thought about the problem and I think for prototyping I should just Box::leak() and work with raw pointers.

            This approach also doesn’t allow you to not learn the borrow checker, since leaking everything is not a good memory management strategy, but might be fine for rapidly iterating on a design.

            EDIT: maybe use a leak!() Macro that does Box::leak(Box::new()) in debug mode but panics on release (as long as you execute once in release it should be fine).

            • Ephera@lemmy.ml
              link
              fedilink
              arrow-up
              2
              ·
              3 months ago

              I tried something like that once. Basically, I was trying to create an API with which sysadmins could script deployments. That involves lots of strings, so I was hoping I could avoid the String vs. &str split by making everything &'static str.

              And yeah, the problem is that this only really works within one function. If you need to pass a parameter into a function, that function either accepts a &'static reference which makes it impossible to call this function with an owned type or non-static reference, or you make it accept any reference, but then everything below that function has normal borrowing semantics again.

              I guess, with the former you could Box::leak() to pass an owned type or non-static reference, with the downside of all your APIs being weird.
              Or maybe your prototyping just happens at the top and you’re fine with making individual functions accept non-static references. I guess, you’ll still have to try it.

              Since you’re already at the bargaining stage of grief programming, maybe you’re aware, but Rc and Arc are the closest you can get to a GC-like feel. These do reference counting, so unlike GC, they can’t easily deal with cyclic references, but aside from that, same thing.
              Unfortunately, they do still have the same problem with passing them as parameters…

              • calcopiritus@lemmy.world
                link
                fedilink
                arrow-up
                1
                ·
                3 months ago

                The good thing about Box::leak() is that it returns a raw *mut pointer. So you need unsafe{} to dereference it. Might as well: let my_ref = &mut unsafe{*ptr}; while you are at it, so you have a perfectly normal rust reference, so the function signatures don’t need any change.

                The problem with Rc is that it would also require a RefCell most of the time. So the whole thing would be filled with Rc<RefCell<T>>. With the required .borrow_mut(). It would both do a pain to do and undo.

                And of course I want to undo it, because RC is a shitty GC.

    • mox@lemmy.sdf.org
      link
      fedilink
      arrow-up
      1
      ·
      3 months ago

      The cool kids in systems programming are using Rust now.

      Can you explain what you mean by “the cool kids”?

  • mox@lemmy.sdf.org
    link
    fedilink
    arrow-up
    11
    ·
    edit-2
    3 months ago

    What new direction is D taking that has you worried? Maybe I should watch out for it, too. :)

    one of the features I dislike the most in C/C++ is the super slow and super obsolete precompiler with its header files,

    Are you sure you should lump those two languages together? In my experience, C++ preprocessing can be slow (especially when you use templates), but not C. I shudder to think what preprocessor shenanigans the C libraries you’ve used might be doing to make compiling with them super slow. (LLVM isn’t exactly known as a speed demon, though; maybe you’ve run into that?)

    In any case, I guess that rules out transpiled languages like Nimskull (work in progress) and its parent language.

    Have you looked at Odin?

    Maybe Vale?

    There is Jai (work in progress), though I haven’t looked closely enough to know if it fits your needs. (I’m not sold on Jonathan Blow’s judgment.)

    I suspect there are few languages well suited to both system and game programming (unless you mean game engine programming) that avoid all the things you seem to dislike. If you find one, I hope you’ll write about it here. If not, there’s always the option of using two languages.

    • Hawk@lemmynsfw.com
      link
      fedilink
      arrow-up
      3
      ·
      3 months ago

      There is also zig, Go and Rust.

      No language is perfect, but those languages have some features that are nice.

        • mox@lemmy.sdf.org
          link
          fedilink
          arrow-up
          6
          ·
          3 months ago

          Also, I don’t think Go is generally considered a systems programming language.

          • Hawk@lemmynsfw.com
            link
            fedilink
            arrow-up
            2
            ·
            3 months ago

            I agree, it’s not often considered a systems programming language and it may not be the perfect tool here.

            However, it is worth mentioning that cgo Can serve as a escape hatch depending on the use case.

        • Hawk@lemmynsfw.com
          link
          fedilink
          arrow-up
          4
          ·
          3 months ago

          Ah my bad, didn’t read.

          Odin is a nice choice then, beef is another small bespoke language.

  • FizzyOrange@programming.dev
    link
    fedilink
    arrow-up
    13
    arrow-down
    2
    ·
    3 months ago

    Rust is the obvious answer, though I dunno how suitable it really is for games - the most popular game engine is Bevy and I’m not sure I like it too much. Also there seems to be much more focus on game technology than making actual games.

    Don’t worry about it being “functional” though. It did support lots of FP features but the typical style is much more like imperative C++ than Haskell.

    I would also look into Zig though.

    • ZILtoid1991@lemmy.worldOP
      link
      fedilink
      arrow-up
      5
      arrow-down
      4
      ·
      3 months ago

      I have talked to people about Rust gamedev (including those who left Rust for D due to gamedev), and it’s not a very good one, due to the functional aspects. Outsiders often joke about how Rust has more game engines than games.

      Zig has the header file problem. Header files were originally created to get around memory limitations of old workstations, that no longer exist. They also complicate coding, since you now often have to implement things at two places at once. However, Zig not only copied C++'s multi-inheritance, but also its header files, without understanding the actual reason why it existed in the first place.

      • Mia@lemmy.blahaj.zone
        link
        fedilink
        arrow-up
        12
        ·
        edit-2
        3 months ago

        I’ve found working with Rust and Bevy to be quite pleasant. If you’re used to working with ECS, I suggest you at least give it a go.
        Rust is as functional as C++ 20 with ranges and views is, which is to say it isn’t. Not sure where you got that impression from, but while it does borrow some ideas from functional languages, it’s still very much a procedural one.

        Zig doesn’t have headers, nor inheritance. Again, not sure where you got that from, but Zig is basically a modern C, so there’s no OOP anywhere, let alone multiple inheritance.

        As for what to use, I think they’re both viable alternatives. I lean more towards Rust, but that’s just due to familiarity. Odin also looks like a viable option, if you don’t mind a smaller ecosystem.
        If you want a garbage collected language, then I’d go for C#. Despite its historic reputation as a Windows only language, it’s been cross platform and open source for roughly a decade at this point. I find it great to work with.

        • ZILtoid1991@lemmy.worldOP
          link
          fedilink
          arrow-up
          2
          arrow-down
          2
          ·
          3 months ago

          Issue with C# is, that it’s quite far away from a system language, and I would have to write the engine’s main core in some more system-level language, and I don’t consider it good practice to write every component that doesn’t directly interfacing with the OS in a trendy scripting language.

          • Mia@lemmy.blahaj.zone
            link
            fedilink
            arrow-up
            7
            ·
            edit-2
            3 months ago

            The fact that it can be used as a scripting language doesn’t mean it’s a scripting language. You could use C++ as a scripting language as well, but it would suck.
            C# even supports native compilation nowadays, not just JIT, so it’s definitely not a lowly scripting language.

            Anyways you’ve got options. Go may also be one of them if you want GC, I forgot to mention it.

      • 0x0@programming.dev
        link
        fedilink
        arrow-up
        3
        ·
        3 months ago

        since you now often have to implement things at two places at once.

        Huh? Header files should only have declarations, unless you’re screwing around with templates.

  • Dark Arc@social.packetloss.gg
    link
    fedilink
    English
    arrow-up
    8
    arrow-down
    1
    ·
    3 months ago

    There’s no precompiler in C++. There’s a preprocessor but that’s something entirely different. It’s also not a slow portion of the compile process typically.

    C++ is getting to the point where modules might work well enough to do something useful with them, but they remove the need for #include preprocessor directives to share code.

    • BatmanAoD@programming.dev
      link
      fedilink
      arrow-up
      7
      arrow-down
      1
      ·
      3 months ago

      OP clearly means “preprocessor”, not “precompiler”. You’re right that preprocessing itself isn’t slow, but the header/impl split can actually cause some slowness at build time.

      • Dark Arc@social.packetloss.gg
        link
        fedilink
        English
        arrow-up
        2
        ·
        3 months ago

        Slow compared to what exactly…?

        The worst part about headers is needing to reprocess the whole header from scratch … but precompiled headers largely solve that (or just using smaller more targeted header files).

        Even in those cases there’s something to be said for the extreme parallelism in a C++ build. You give some of that up with modules for better code organization and in some cases it does help build times, but I’ve heard in others it hurts build times (a fair bit of that might just be inexperience with the feature/best practices and immature implementations, but alas).

        • BatmanAoD@programming.dev
          link
          fedilink
          arrow-up
          2
          ·
          3 months ago

          Slow compared to just chucking everything into a single source file, actually: https://github.com/j-jorge/unity-build

          That’s only true for clean builds and even then isn’t universally true, and of course there are other reasons not to do unity builds. But the existence of the technique, and the fact that historically it has sped up build times enough for various projects to adopt it, does show that the C++ model, with headers and separate compilation units, has some inherent inefficiency.

          • Dark Arc@social.packetloss.gg
            link
            fedilink
            English
            arrow-up
            2
            ·
            3 months ago

            Sure, there’s a cost to breaking things up, all multiprocessing and multithreading comes at a cost. That said, in my evaluation, single for “unity builds” are garbage; sometimes a few files are used to get some multiprocessing back (… as the GitHub you mentioned references).

            They’re mostly a way to just minimize the amount of translation units so that you don’t have the “I changed a central header that all my files include and now I need to rebuild the world” (with a world that includes many many small translation units) problem (this is arguably worse on Windows because process spawning is more expensive).

            Unity builds as a whole are very very niche and you’re almost always better off doing a more targeted analysis of where your build (or often more importantly, incremental build) is expensive and making appropriate changes. Note that large C++ projects like llvm, chromium, etc do NOT use unity builds (almost certainly, because they are not more efficient in any sense).

            I’m not even sure how they got started, presumably they were mostly a way to get LTO without LTO. They’re absolutely awful for incremental builds.

            • BatmanAoD@programming.dev
              link
              fedilink
              arrow-up
              1
              ·
              3 months ago

              Yeah, I mean, I tried to be explicit that I wasn’t recommending unity builds. I’m just pointing out that OP, while misinformed and misguided in various ways, isn’t actually wrong about header files being one source of slowness for C++.

  • DrDeadCrash@programming.dev
    link
    fedilink
    arrow-up
    7
    arrow-down
    1
    ·
    3 months ago

    C# is a great language, I don’t know much about game dev but I know unity and godot game engines have good support for c#. You can target Windows/Linux/Mac on all the common architectures. All the build tools are available on the command line if that’s your thing.

    • Mihies@programming.dev
      link
      fedilink
      arrow-up
      4
      ·
      3 months ago

      C# is awesome, however it has one big issue when it comes to games - garbage collection that can start at any moment and you have no control over it. There are ways to workaround but none is 100%. OTOH from similar level languages there is Swift that does reference counting instead and doesn’t have this problem, albeit has a reference counting problem (where cyclic reference would create a memory leak, but this problem is solvable).

          • ZILtoid1991@lemmy.worldOP
            link
            fedilink
            arrow-up
            2
            arrow-down
            1
            ·
            3 months ago

            Classes can be useful for abstraction. Just because they often overused doesn’t mean they’re bad.

            Without an explicit class, I would either:

            • had to reimplement them in a language without them (which looks extremely ugly and can be unsafe),
            • create an “omnistruct” that keeps track of all posssible field (only looks a bit ugly),
            • use uglier virtual functions for cases when I would need local states (doStuff(cast(void*)&localstate, values) vs localstate.doStuff(values)).

            While structured programming was a godsend to the chaos preceding it, newer programming paradigms should have been instead seen as tools rather than the next dogma. OOP got its bad name from languages that disallowed its users to develop without classes, and enterprise settings making its devs to implement things that could have been simple functions as classes, sometimes complete with factories.

            Same is with functional programming. There’s clearly a usecase for it, but isn’t a Swiss-army knife solution for all problems of programming.

            • MajorHavoc@programming.dev
              link
              fedilink
              arrow-up
              3
              ·
              edit-2
              3 months ago

              Well said.

              Here I am trying to wind people up and you’re responding with thoughtful nuanced consideration.

              You make some great points.

              I’ll add - for folks reading along - I do think a class is still almost always an anti-pattern, even with all the OOP class function and factory pattern stuff removed.

              I also feel (as you referenced):

              • Functions being forced to reside inside objects is just stupid.
              • Factory patterns are horrible, because they mix config into program code, maximizing uncertainty when debugging

              And also:

              • Inheritance is almost always a worse idea than an interface.
              • classes tend to have additional fancy tooling to make it easier to carry state data around - which is usually a bad idea

              State data is a necessary evil in most programs.

              I’ve found that most advanced class object implementations treat program state data more like a pet than a threat.

              Sorry for the long response - I know you don’t need it - you know what kind of tool you’re looking for.

              I figure they extra detail above might provide food for thought for folks reading along who are surprised there’s even contrasting opinions on classes.

              (And I feel a little bad for not really posting anything very useful earlier in the thread.)

            • BatmanAoD@programming.dev
              link
              fedilink
              arrow-up
              2
              ·
              3 months ago

              You don’t need to do any of those things with Go or Rust. Interfaces/traits provide the capability for dynamic dispatch.

        • calcopiritus@lemmy.world
          link
          fedilink
          arrow-up
          7
          ·
          3 months ago

          Interfaces (traits in rust) are the best imo. Way better than raw structs in C or the mess that is inheritance.

          What I don’t like about go’s interfaces is that they’re implemented implicitly. I much prefer java’s and Rust’s way to implicitly say which classes/structs extend/implement which interfaces.

      • BatmanAoD@programming.dev
        link
        fedilink
        arrow-up
        7
        ·
        3 months ago

        These are extremely superficial observations. You should learn more about each of these languages before dismissing them; Go is especially easy to learn.

        (I quite dislike Go, actually, but “it has no classes” is nowhere near a valid reason not to learn a language.)

  • calcopiritus@lemmy.world
    link
    fedilink
    arrow-up
    3
    ·
    3 months ago

    Another user already proposed Odin, but no one yet Jonathan blow’s unnamed programming language (people call it jay). Those are the 2 programming languages that came to mind when I think of game development.

    I haven’t tried either so I don’t know if they fit you, but they are new languages so they should avoid java’s and C++'s pitfalls.

  • monobot@lemmy.ml
    link
    fedilink
    arrow-up
    2
    ·
    3 months ago

    I don’t know about game dev, buy SerenityOS guys are flirting with Swift.

    If it wasn’t from Apple, I would be all over it. They basically took different languages and most of C++ devs made fastest advance in Swift. Rust I do like and support, but is too confusing for amout of free time I have.

    • hydroptic@sopuli.xyz
      link
      fedilink
      arrow-up
      6
      ·
      edit-2
      3 months ago

      Swift is… not a great language. It’s got some promise but goddamn does it have a “designed by committee” feel to it; they just keep throwing on features like they’re going out of fashion and it’s getting ridiculously complex. Just the syntax alone is a bit of a nightmare – soooo many keywords and symbols. It’s also extremely hard to predict how well Swift code will perform, in large part due to ARC (automatic reference counting) memory management, which is a huge downside for game development. And don’t even get me started on the new concurrency stuff…

      Just as a side note, it’s not purely an Apple project nowadays. They’re still the “project lead” but it’s not exclusively theirs anymore. Still, regardless of that, at least personally I really couldn’t recommend it especially to someone looking to get into game development.

  • 31337@sh.itjust.works
    link
    fedilink
    arrow-up
    3
    arrow-down
    1
    ·
    3 months ago

    C# is actually pretty nice. Ecosystem, not so much, but D doesn’t really have one anyways :)

    • ZILtoid1991@lemmy.worldOP
      link
      fedilink
      arrow-up
      2
      arrow-down
      1
      ·
      3 months ago

      It’s too high level for my usecase, so unless I either use a preexisting game engine, or develop mine using a system language, so C# is only good as a scripting language in my usecase, and sometimes you want “hard-code” new features, not script them.

      • MajorHavoc@programming.dev
        link
        fedilink
        arrow-up
        2
        ·
        3 months ago

        C# is only good as a scripting language in my usecase, and sometimes you want “hard-code” new features, not script them.

        My recent experience with C# suggests you might have a much better time with it, than you think.

        C#'s compile phases are nuanced and achieve surprisingly quick results, now.

        If it’s been awhile since you used C#, you could be happily surprised.