👾 Game Player 🎲 Dice Jailor 💻 Functional Typer 📹 Content Creator 🎧 Air Wiggler 🏹 Arrow Shooter ⛔️ Out of Charac

dneaves.com

  • 0 Posts
  • 29 Comments
Joined 3 years ago
cake
Cake day: July 10th, 2023

help-circle
  • I don’t think Hello Games lied as much as you may think. Sony lied, and others layered their own expectations on top.

    HG turned to Sony for publishing and marketing help. Sony, like any game publisher, wants to get as many sales as possible, preferrably on release day to look the best (for further marketing when sales slow down: “X million dollars on release day”/“Y copies sold on release day” kind of stuff). So Sony had a huge hand in promoting the game, and undoubtedly crunched time on HG, reducing their ability to get what they wanted to out the door.

    Plus, people hear what they want to hear and read what they want to read sometimes. Game journalists and streamers and influencers and such layered their expectation on each other, chalking up the game to more than was promised by HG, only to be disappointed when it wasn’t. Murray even said the day before its release that it “maybe isn’t the game you imagined”.

    And sure, not to absolve HG of all the blame here, there was underdelivery and bugs. They got swept up in a storm of shit larger than they were ready for. They probably could have said more at the bungled release, but I wonder how much (if any) they couldn’t because of Sony’s hands in the PR. Iirc they were allowing returns of the game past normal return timelines? Given all of that, though, they committed to their game, even when Sony left, and even if players left and didn’t come back. That’s why people talk about it’s comeback story.

    For Cyberpunk, though, I’m less supportive of that comeback story because CDPR had other majorly-known games (Witcher). They knew how game-dev-crunching and publisher pressure reduces their ability to deliver. They understood how marketing grows hype and expectations of their games. They even saw how NMS’s release went, and they still fumbled their release horribly. I’m happy for those that play CP2077 and enjoy it today, but I’m less on-board for that one.


  • I think the shallowness of understanding also stems from the codebase itself, and moreso that than the Ai finding where something is.

    A poorly organized codebase, dynamic file imports lsp’s can’t follow, lack of annotations on unclearly-named arguments, etc. are way worse for understanding a codebase than Ai saying “the thing you need is this method”, which Ai could also explain how it got there at least. At that point, Ai is a better than what they would have without it.

    Write clean, understandable code. Document it, too. Everyone will thank you


  • Tbh, I’d love to be able to use this less for games and more for just Android apps.

    I’d love to move more to a less-Google-owned mobile platform that still has the apps I use and the power to run things. I think the two frontrunners are like /e/OS or GrapheneOS.

    But with Lepton: A) there’s a better chance of the idea of a Linux-non-Android phone, since Lepton could allow Android apps run on a Linux phone; or B) make Linux tablets better, again with Android apps.

    I also have an idea in my head that next “upgrade” I can afford I’ll ditch my phone and go for a smartwatch (with 4G/5G) and a tablet (for apps). The best pairing is probably from Samsung, which unfortunately is both Android/Google and now focused on promoting AI features (ew). I’d go for GrapheneOS if I could put it on a tablet of suitable specs, and if a smartwatch would work well with it (which the watch would probably still be Samsung’s, but maybe RePebble can do something great?).

    But if I could use a Linux tablet? That’s a computer at that point, and I could also benefit from having a laptop since there’s also things an Android device couldn’t do that a computer could (I’m a software dev, it’d be painful on Android). Waydroid/Lepton then supplements the part where there are things Android can do that computers can’t, which is just “apps the developer didn’t make a webapp/computer app for”. Still would have to figure out the watch part, but it’s a start




  • Functional language developers are obsessed with side effects but I rarely ever see problems with it in real code. Like I can remember once in maybe 10 years setting a developer write a “get” method that also wrote to a file. Caught during code review, rewritten easily.

    While, sure, get methods writing files could happen in side-effectful code, the side-effect concern is less about that and more of expectations. With OOP languages, class methods can create a dichotomy of expected returns: Using a list reversal as an example, will a list.reverse(some_list) function reverse the list in-place, or return a copy of the reversed list and leave the original in-tact? To know the answer, you have to check the docs or the type signature (which, yes, is easy, but the answer isn’t obvious). Which, the main concern is trying to debug things “magically changing”, since nested function calls and inherited function calls can modify something from layers upon layers of abstraction away.

    FP languages tend to not have this dichotomy, with very few exceptions like IO in Haskell, ports in Elm and Gren, external functions in Gleam, or FFI in Haskell, to name some ways from languages I know, all of which usually move the control of the program outside the language’s “default area”, anyway. Outside the exceptions, to reverse a list a reverse function needs to be given that list explicitly, and it also will be returning a copy of the list reversed, only and always






  • I find real-world examples help grasp concepts for me. I’ll use an example like a video platform (like Youtube) as an example for this:

    One-to-one: for each one User, you maybe only allow one [content] Channel (or, could be one-or-none, meaning a User may have one Channel, or may use use their User account to be a viewer and have no Channel. You might decide to change this later to be one-to-many, but for the example let’s say you don’t). All the data could be stored just on the User entity, but maybe you decided to separate it into two tables so you don’t need to query the User entity which has sensitive info like a password, email, or physical address, when you just need a Channel. For each Channel, there is a foreign key pointing to the (owning_)user_id, and this is “unique”, so no duplicate id’s can exist in this column.

    One-to-many (or Many-to-one): for each one Channel, there may be many Videos. You could use a relational table (channel_x_video), but this isn’t necessary. You can just store the (owning_)channel_id on the Video, and it will not be unique like the prior example, since a Channel will have many Videos, and many Videos belong to one Channel. The only real difference between “one-to-many” and “many-to-one” is semantic - the direction you look at it.

    Many-to-many: many Users will watch many Videos. Maybe for saving whether a Video was watched by a User, you store it on a table (by the way, this example might not be the best example, but I was struggling to find a good example for many-to-many to fit the theme). Although each video-to-user relation may be one-to-one, many Videos will be watched by one User, and many Users will watch one Video. This would be not possible to store on both the Video or the User tables, so you will need a relational table (video_x_user, or include “watched” in the table name for clarity of purpose). The id column of each row is irrelevant, but each entry will need to store the video_id and the user_id (and neither will be unique), as well as maybe the percent watched as a float, the datetime it was watched, etc. Many-to-many relationships get very complicated often, so should be used carefully, especially when duplicate combinations of a_x_b can occur (here, we shouldn’t store a new row when a user watches a video a second time)


  • That’s how languages should all work?

    While I agree, should be is not is. Also, Javascript is still a widely used and favored language, despite it’s flaws.

    Sometimes people need to be convinced that there’s something better, hence all the articles of “Javascript devs discovering actual typing”, as you mentioned. Although it seems like the author already knew there’s better (I see Typescript and Rust on their Github), that they were just sharing Gleam.

    As for specifically Gleam, I will say it’s a very nice language. Very simple to understand (with one minor exception: I personally find the use keyword is a bit odd), strong typing, no collections of mysterious symbols (cough, Haskell), no metaprogramming, no lifetimes, no borrowing, no unclear polymorphism, no pointers, no nonsense. I like it, and am excited to see it grow


  • To be fair, all three can probably do what you’re asking for, in building a desktop application. So the real question comes as which flavor of language do you want to write. The only language of the three I can’t speak on is Ruby, as I haven’t used it.

    Python is a “scripting language”, but by that token technically so is Javascript. It’s an immensely popular language due to its simple syntax, yet complex features as you get better with it. Python can build large-ish applications: web apps, desktop apps, terminal apps, and yes also of course AI, bulk data processing, etc. For GUI applications, I’ve personally used pyqt (4? 5? 6?)

    Much of the same can be said for Javascript. As you said, there are “negative opinions” about JS, but everyone has their opinions (most factually-based) on the goods and bads of languages (although, yes, JS does get more negative opinions than others). Yet, Javascript is still a widely used language, and you’ll probably end up needing learning it anyway if you decide to go into web development.

    What I personally suggest is this:

    • See the learn x in y minutes pages for Python, Javascript, and Ruby. Make sense of the quick-tour of the languages.
    • Make a simple project using each of the three languages. Something that just reads something from STDIN, does some work, prints stuff, as an example. This helps you get to know the basics of the syntax, tooling, and quirks of a language, and helps you narrow down which language you’d like to be working further with.
    • Pick one of the languages you’re leaning in favor of and go build your application. If you come to a point where you feel like the language you choose is no longer suitable for what you wanted to do, you can always retry with another language, and then you will know at least a fair part of more than one language.

  • When the enum reaches your JSON, it will have to be a string (as JSON does not have a dedicated “enum” type). But it at least ensures that languages parsing your JSON will should have a consistent set of strings to read.

    Consider this small bit of Elm code (which you may not be an Elm dev, and thats okay, but it’s the concept that you should look to get):

    -- A Directions "enum" type with four options:
    -- North, East, South, West
    type Directions
        = North
        | East
        | South
        | West
    
    -- How to turn each Directions into a String
    -- Which can then be encoded in JSON
    directionsToString : Directions -> String
    directionsToString direction =
        case direction of
            North -> "north"
            East  -> "east"
            South -> "south"
            West  -> "west"
    
    -- "Maybe Directions" since not all strings can be parsed as a Directions.
    -- The return will be "Just <something>" or "Nothing"
    directionsFromString : String -> Maybe Directions
    directionsFromString dirString =
        case dirString of
            "north" -> Just North
            "east"  -> Just East
            "south" -> Just South
            "west"  -> Just West
            _       -> Nothing
    

    The two functions (directionsFromString and directionsToString) are ready to be used as part of JSON handling, to read a String from a key and turn it into a Directions enum member, or to turn a Directions to a String and insert the string to a key’s value

    But all that aside, for your restructuring, and keeping with the license plate example, both type and license number could be contained in a small object. For example:

    {
        ...
        "licensePlate": {
            "type": "government"    <- an enum in the language parsing this
                                       but a string in JSON
            "plateNumber": "ABC123"
            ...
        }
        ...
    }
    

  • If its something that represents mutually exclusive states, like the license plates examples (Gov’t, Embassy, Learner), an enum like 4wd mentioned is a better idea than many boolean keys. This would also be the switch/case question you posed. For a “regular case”, I would include that in the enum, but if you create an enum that only contains “special cases”, you can always set it to null.

    On the case of booleans, I would suggest avoiding them unless it is necessary, and truly a binary (as in, two-option, not binary numbers), self-contained-in-one-key thing (obligatory anti-boolean video). If the use case is to say what a different key’s object represents, you don’t need it (see: enums. You’ll thank yourself later if you add a third option). If the use case for using it is saying another key contains value(s), you don’t need it. Many languages can handle the idea of “data is present, or not present” (either with “truthy/falsey” behavior interpreting “data-or-null”, or “Maybe/Option” types), so often “data-or-null” can suffice instead of booleans.

    I would suggest trying to always include all keys of a present object, even if it’s value is null or not applicable. It will prevent headaches later when code might try to access that key, but it isn’t present. This approach might also help you decide to reduce the quantity of keys, if they could be consolidated (as in taking booleans and converting to a state-like enum, as mentioned above), or removed (if unused and/or deprecated).


  • You can feign immutablility on class attributes by playing with __setattr__. I don’t remember the exact way to do it, but its roughly like this:

    class YourClass:
        def __setattr__(self, name, value):
            if not hasattr(self, name):
                super().__setattr__(name, value)
           else:
                # handle as you wish if the
                # attr/value already exists.
                # pass, raise, whatever
    

    I say “feign immutability” because there are still cases in which an attr value can change, such as:

    • the underlying attribute contains a list and appending to the list
    • the underlying attribute is a class and modifying the class’s attributes
    • pretty much anything that does “in place” changes, because so much of python is referential and has side effects.



  • Neat. I use Zed at work, but now also having it on my personal desktop will be nice. Bye, VSCode.

    On my system, just one note that it didn’t render a menu bar. Not that I use it much anyway, just had to find the default keybind to open the keybinds config (btw: ctrl K |> ctrl S) and pasted what I used from work (then bulk-replaced all cmd’s with ctrl’s)

    Theme change was not sticking on first launch, but second launch I guess it realized “Oh, I’m supposed to be this color now. Got it”. Ligatures don’t do, but it is a preview and that’s just an aesthetic.


  • Elm

    In short, it’s ruined my expectations of languages. It’s a functional language, like the style of Haskell, and transpiles to html or js (its meant for web). There’s very little that it allows for going wrong, and for things that could fail, it either tells you to port that out to JS and bring it back when you’re done, or you have to handle a Result type or Maybe type.

    It sounds strict, yes, but not having to deal with issues later is so nice.