1. 5

    You can’t write functions with a receiver in a different package, so even though interfaces are ‘duck typed’ they can’t be implemented for upstream types making them much less useful.

    am i mistaken or does embedding the upstream type this, but in reverse? the composition is often overlooked in go, while it is one of the best things. not being allowed to fiddle around in other packages is a good restriction as this is a symptom for other problems.

    1. 4

      Yes, embedding types is one way to solve this in Go. Rust and Go are very different in this regard.

      In Rust, it’s common to extend a type with additional functionality using traits so you don’t need to convert between the types. In Go this isn’t possible. See this for an example. The basic AsyncRead provides low level methods and AsyncReadExt provides utility functions. It means that if someone else implements AsyncRead for a type, they can use any of the AsyncReadExt methods on it (provided AsyncReadExt is imported). Something like that just isn’t easily possible in Go to the same level because it’s only possible in Rust due to generics.

      1.  

        if you extend a type, can your extension affect what the original code was doing? Part of the motivation for Go’s typing system is that it’s designed to avoid the fragile base class problem. As someone with little Rust experience, it’s not clear how extending types in Rust avoid a fragile base class scenario.

        1.  

          The original code is unaffected. The alternative implementation is only available to code that uses the implemented trait and Rust doesn’t allow conflicting method names within the same scope, IIRC, even if they’re for two different traits on the same type.

          1.  

            You can. But when you try to call such a method, if it is otherwise ambiguous, then Rust will yield a compiler error. In that case, you have to use UFCS (“universal function call syntax”) to explicitly disambiguate: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a602c67af78a73308808e9a45a51ead4

            One could argue Rust programs could suffer from the fragile base class problem via default method impls on traits. But it’s not something I’ve experienced much (if at all) in practice. Rust doesn’t have inheritance, so you don’t really wind up with complex inheritance hierarchies where this sort of complexity is difficult to manage.

            1.  

              I’ve seen it happen with extension libraries like itertools that want to add functionality that makes sense in the base trait. It’s always possible to avoid it by using UFCS, but at that point you already lost method chaining and might as well use a free function.

              https://github.com/rust-lang/rust/issues/48919

          2.  

            No, because traits are only available to use if they’re imported. So you’re not actually modifying the actual type, but extending it.

          3.  

            I don’t know rust, but isn’t that kind of having io.Reader in go and other types which take io.Reader implementations and implement other functionality on top of that? Like bufio.Reader?

            1.  

              Wrapping a type to implement an interface is somewhat similar. But in Rust, you do not have to write a wrapper to implement traits. E.g. have a method to reverse code points of a String you can just define a trait and implement it directly for String:

              trait ReverseCodepoints {
                fn reverse_codepoints(&mut self);
              }
              
              impl ReverseCodepoints for String {
                fn reverse_codepoints(&mut self) {
                  // Implementation.
                }
              }
              

              After that you could just call somestring.reverse_codepoints() when the trait is in scope. It’s often more convenient than wrapping, because you do not have to wrap/unwrap depending on the methods you need (or write delegation methods).

              That said, there are some limitations in that the orphan rules have to be satisfied. Very roughly, this means that the implementation should be defined in the same crate as the trait or as the type the trait is implemented for. Otherwise, two different implementations could be defined for the same type. If you cannot satisfy the orphan rules (e.g. because the type and trait come from another trait), you do need a wrapper type.

              1.  

                This seems dangerous, since now users of the original type may not realize it has suddenly grown new talents.

                1.  

                  It actually doesn’t, because the function is not associated with the type. It’s associated with the pair of (type, trait).

                  You have to import the trait ReverseCodepoints before you can call it.

                  1.  

                    Or, worse yet, that existing talents may have been redefined. (Is that possible?)

                    1.  

                      Nope - and even if you could override an impl, the orphan rule would stop you overriding impls you don’t own.

                      1.  

                        👍 Good to hear.

                  2.  

                    thanks for the explanation!

                    It’s often more convenient than wrapping, because you do not have to wrap/unwrap depending on the methods you need (or write delegation methods).

                    usually the wrapped versions tend to be used from there on (at least the way i use them ;), so that’s not really an issue for me. i like the verbosity of go, which may be a bit unusual, but i like that things are written down explicitly.

                  3.  

                    I had forgotten about interfaces somehow. Yes, sort of. But you’re limited to wrapping stuff one level at a time and you have to actually make new wrapper types.

                    1.  

                      i kind-of like that in go i have to add new types for new functionality, but i see why traits may be good (without having written rust yet..)

              1. 3

                This is a great article!

                I loved both the C part (which did not surprise me at all) and the Rust part (where everything was new to me). I am left with the somewhat strange feeling that I actually prefer the C way of doing things. The “simple” Rust program does too many things under the hood and this makes me uncomfortable.

                1. 8

                  you prefer the subtly broken implementation that half works on latin-1 left-to-right text? Imagine this on japanese or korean, or in a right to left script like arabic or hebrew. You can still use OSstring in rust or access the raw bytes if you need to, but why not use the safe version by default?

                  1. 1

                    The thing is that both implementations may be broken, but the C code is more explicit. When it fails, or it receives bad input, I can look at the code that I have in front of me and understand why it fails, and maybe how to solve it. Let us say that the rust code receives a malformed argument string, where an invalid utf sequence contains a byte with the value ’ ’. What will happen? Will the iterator break? Or the upper case conversion? Or will my program break before even the first line of my program? I always get this kind of anguish about the inevitable impredictability when working in “high level” languages.

                    1. 11

                      Let us say that the rust code receives a malformed argument string, where an invalid utf sequence contains a byte with the value ’ ’. What will happen?

                      if I’m understanding your question correctly it’ll panic when it attempts to put it into a string, which is what the example in the article shows. What it won’t do is happily continue until it reads outside its buffer or causes some other error by corrupting memory.

                      When it fails, or it receives bad input, I can look at the code that I have in front of me and understand why it fails, and maybe how to solve it.

                      you may be able to, I don’t think I can. I don’t think I’m particularly inept, but this is incredibly subtle and complicated work that people get wrong all day every day

                      1. 8

                        The nice thing about Rust here is that “breaking” will usually consist of the program panicking and exiting without doing anything unexpected or dangerous. Most of the time, such panics are caused by unwrap or expect statements where you didn’t think an error case could happen, but it infact did.

                        What seems to be very common with the C bugs, and almost, but not quite entirely, unheard of in Rust (and other safe languages) is memory unsafety issues, including leaking, corruption, disclosure, and even RCE based on coding errors.

                        1. 5

                          Let us say that the rust code receives a malformed argument string, where an invalid utf sequence contains a byte with the value ’ ’. What will happen?

                          That depends on how you retrieve the arguments. If you want the user to pass only valid Unicode, you’d retrieve the process arguments with std::env::Args(), which will panic if any of the arguments are not valid Unicode. This enforces argument validity at the boundary of your program.

                          If arbitrary byte sequences make sense, too, you’d retrieve the process arguments with std::env::ArgsOs.

                          If you want valid Unicode arguments, but want to handle malformed input gracefully rather than panic, you’d retrieve the process arguments with std::env::ArgsOs, try to parse them to UTF-8 with OsStr::to_str, and handle success and failure of the parsing attempt.

                          match arg.to_str() {
                              Some(arg) => println!("valid UTF-8: {}", arg),
                              None => println!("not valid UTF-8: {:?}", arg),
                          }
                          

                          All of this is set out more elaborately in the article, starting at Now for some Rust.

                        2. 1

                          C strings are null terminated arrays of bytes, as they are defined in the standard. Sometimes those bytes represent text, sometimes they do not. Some text is encoded in ASCII, some in UTF-8, and some in other encodings. Some Unicode encodings, like UTF-16, can’t even be stored in a C string, because they contain null bytes.

                          This isn’t “subtly broken”, it’s just a different level of abstraction to Rust.

                        3. 4

                          Understandable take. What kind of under-the-hood manipulation of raw strings do you imagine needing? (Rust does provide ready access to the bytes of a String as needed, just in case.)

                        1. 4

                          I used this approach to learn Rust! I already knew Ruby, so I prototyped a game project in it. Then, using native extensions via helix and rutie, I replaced the Ruby code section by section until the entire game was written in Rust. Learning the new language and its unfamiliar paradigms proved easier for me, compared to academic study, when I already had the concrete context of familiar code to guide me.

                          1. 6

                            I’ve attempted my fair share of rewrites and had to work with a few legacy systems and yeah, this is definitely good advice. I think it’s best to keep the application running at all times, not only for business reasons but for psychological ones too: not being able to ship the stuff you’re working on for a long while takes a big toll on morale, and having to deal with the legacy bits keeps you grounded in reality and stops you from chasing the pie in the sky of the perfect system.

                            1. 2

                              At one job, I could only watch as my first 4-6 months of work on their total rewrite project was shelved in one go. Needless to say, my personal investment plummeted and I left for another job as quickly as I could. Their loss.

                            1. 28

                              Have done this, can confirm it works. If you have trouble with the political side of things, introduce the strangler as a diagnostic tool or a happy path and start shipping new features under its guise instead of under the legacy system. Arguing for two concurrent system with initially disjoint usecases is easier than a stop-the-world cutover.

                              1. 3

                                Strongly seconding. I’ve seen countless person-hours wasted on trying to replace legacy systems wholesale. IT systems are like cities: They grow organically and need to change organically if you want to avoid displacing whole swaths of the population and causing more harm than good.

                                1. 1

                                  How do you handle downstream consumers of functionality as you strangle the original piece of code? Can’t always force everyone to move to a new API route or use a new class in a library.

                                  1. 7

                                    The best case is not to force them to change anything. In my case, we did exactly as the article mentioned, and slowly transitioned to a transparent proxy. Then slowly we turned on features where API requests were handled by the new code, rather than being proxied to the old code.

                                    1. 4

                                      It’s obviously harder if your API has multiple consumers (some of which you don’t control). One option is to have the proxy expose the same endpoints as the legacy system, though that’s not without its own complications (especially if the technologies are particularly divergent).

                                      1. 3

                                        That’s a political problem, not a technical one. You solve it by building political power in the organisation.

                                        1. 2

                                          Only if the consumers of your API are within your organisation…..

                                          1. 3

                                            For this you need separate gateway service that hosts the API and then forwards to either the new service or the legacy service. It’s also generally appropriate to use the legacy service as the api gateway, and abstract the route through that to the new external service.

                                            Be mindful of added latencies for remote systems.

                                            1. 2

                                              If people are paying you for a working API, I’d struggle to imagine a viable business case for rebuilding it differently and asking customers to change.

                                              1. 3

                                                It happens all the time. That’s one of the reasons that REST APIs are generally versioned.

                                                1. 1

                                                  That still doesn’t solve the problem. The customers still need to transition to the newer version.

                                                  1. 3

                                                    I think our wires are crossed. I was using multiple versions of REST APIs as a counterpoint to the idea that there’s no “viable business case for rebuilding it differently and asking customers to change.”

                                                    That change may even be driven by customers asking for a more consistent/functional API.

                                          2. 3

                                            I’ve normally handled this my making all consumers use a service discovery system to find the initial endpoint, and then using that system to shift traffic “transparently” from the old system to the new one.

                                            This is admittedly a lot easier if your consumers are already using service discovery, otherwise you still have a transition to force. But at least it becomes a one-time cost rather than every migration.

                                        1. 10

                                          Writing more Rust

                                          1. 2

                                            No Rust for me this weekend but only because I’ve been working with it all week. The ray tracer is coming along nicely.

                                            1. 1

                                              Oh wow, you just reminded me that I should work on my raytracer again.

                                              I bought a big book on raytracing a few years ago, had a brief skim through it, implemented the very most basic ideas and promptly put it into my bookshelf and totally forgot about it. It was (I think?) not long after I had completed a graphics course at university where we’d covered and implemented basic raytracing and I wanted to dive deep right into it, but I probably wasn’t quite ready.

                                              1. 1

                                                I’ve been going through this book and have found it very accessible even without a background in matrix math.

                                                1. 1

                                                  https://www.pbrt.org/ this is the book I was thinking of! Found it at last, hidden away in a stack of books.

                                                  1. 2

                                                    Nice! Thanks.

                                                    The third edition is online for free now, too: http://www.pbr-book.org/.

                                            2. 0

                                              This weekend I will do the same

                                            1. 2
                                              • Time with my girlfriend. (It’s Valentine’s weekend!)
                                              • A sleep study. (Quality sleep is a force multiplier for mental health!)
                                              • Working on my game project. (One of my daily habits.) Going to sketch more music with my Pocket Operators in the process.
                                              • Play more of Mistover. It’s strongly inspired by Darkest Dungeon, another excellent game I’ve played, but with a stronger JRPG vibe.
                                              1. 2

                                                Visiting my mom for Christmas and hopefully taking it easy.

                                                Also messing around more with ggez, a lightweight 2D game framework in Rust. We’ll see if I can come up with a graphics API that is better/faster/less buggy but also still easy for a newbie to use. I think I have a good skeleton but it needs some higher-level flesh atop it.

                                                1. 1

                                                  Good luck on that! Looking forward to doing more 2D gaming with Rust, too.

                                                1. 11

                                                  My fiancé and I will be telling our family that we’re gonna actually do it and go get married. Should go great.

                                                  1. 2

                                                    Hell yeah! Happy for yall and wish you two best of luck on everything around that! :)

                                                    1. 1

                                                      Congrats!

                                                    1. 2
                                                      • Verifying that my 401k is set up right before the current enrollment/update period closes.
                                                      • Hopefully playing some Root (board game).
                                                      • Indulging an itch to breed competitive Pokemon that I’ve never felt before Sword/Shield, even going back to Red/Blue.
                                                      • My weekly planning.
                                                      • Decorate the Christmas tree with 3D prints prepared by my girlfriend.
                                                      1. 4

                                                        Getting onto a much earlier schedule, and starting to run the house more proactively than I had in the past. My wife is currently battling a couple of chronic diseases, so I’m trying to learn how to take care of both of us and hold down a job. The plan is to try to get as many work hours in while she’s sleeping as I can, so I don’t have to do so many while also trying to make sure she’s taken care of.

                                                        Been playing Slay the Spire quite a bit, it’s proved to be a really fun game to play while something else is going on in the background.

                                                        For side projects, I started on a Web-based spreadsheet idea over thanksgiving, but it’s more idea than anything right now. I was able to start on a stack-based scripting language for it.

                                                        1. 1

                                                          I loved Slay the Spire. Looking forward to the 4th character DLC?

                                                          1. 1

                                                            I am, dunno when it’ll come out on the Switch. Right now, I’m working on grinding out Ascensions with each of the characters. I’ve not been able to be 100% consistent with any of the characters yet, I just unlocked Ascension Level 2 for the Silent.

                                                            For me, getting lucky/broken enough to get an ascension seems easiest with the Defect, then the Ironclad, and then the Silent. My wins so far have been Defect -> Silent -> Ironclad -> Defect (Asc 1) -> Ironclad (Asc 1) -> Silent (Asc 1).

                                                            It’s fun to see what different ways things can combo into each other, though it seems like artifacts can have a rather strong effect on what does or doesn’t work as well.

                                                        1. 3
                                                          • Practice my Rust via Advent of Code
                                                          • Continue writing 400 words/day of content for my visual novel
                                                          • Post a Patreon update for said visual novel
                                                          • Get work moving on my (regular) novel again
                                                          • And file my expenses at work. (I have a frustrating amount of anxiety around this, despite Expensify making this so easy)
                                                          1. 3

                                                            Relaxing with my partner after a week of travel and breaking open Pokemon Sword or Shield (probably Sword).

                                                            1. 4

                                                              NaNoGenMo!!!! Working on my next great American (generative) novel! As is now the tradition, I’m also updating the tool I use to create Tracery grammars pos2tracery

                                                              1. 1

                                                                Jellies! I’ve won NaNoWriMo before and have been meaning to get into NaNoGenMo.

                                                              1. 4

                                                                Working on my visual novel (in Ren’Py), playing Outer Worlds, and relaxing before traveling to Maryland.

                                                                1. 3

                                                                  Am I missing something or did the author just restate classic manager techniques as if they were novel ones? I didn’t notice any suggestions that I didn’t already assume a manager was doing in the background.

                                                                  1. 2

                                                                    It’s the circle of life. Young dev starts working. Young dev is so smart and everyone is dumb. Young dev points out stupidity of things not understood. Young dev ages, convinces others to stop stupiding.

                                                                    It’s hard for people to understand everything that’s happening and what’s not visible directly and immediately. Some people assume that stuff is unnecessary. Sometimes it is unnecessary.

                                                                    I look forward to OP’s blog post in 10 years about whatever wonderful communication meeting technique. Or OP goes into consulting and writes a post every month on the subject.

                                                                    I think it’s wild reading Brooks’ Mythical Man Month that was written 40 years ago and same themes still apply.

                                                                  1. 11

                                                                    I swear by my Bullet Journal. It replaced a text file-based system (a sort of pseudo org-mode) that depended too much on having a laptop or other computer.

                                                                    • The friction of having to rewrite todo items by hand helps me keep my lists short. That significantly reduces the stress of giant, “eternal” digital lists.
                                                                    • Keeping it physical means that my phone and all its countless distractions can stay in my pocket.
                                                                    • Marking things as done with a pen feels like more of an accomplishment than tapping a digital checkbox. All the more dopamine.

                                                                    Their app is a big help, too.

                                                                    1. 7

                                                                      I personally found pen and paper to still beat digital note taking software. For some reason I always spend more time tweaking the software than actually using it. Either that or I get distracted by something else. With pen and paper you don’t have much to do but write, so I find it easier to stay focused.

                                                                      1. 3

                                                                        Exactly this, too. I had a small suite of scripts supporting my text file system. I fell off the wagon with it, in part, because of the effort that would have been involved in setting everything back up after a system reinstall. With a Bullet Journal, I just buy a new notebook and a new pen.

                                                                      2. 2

                                                                        I do something similar, though it’s far more basic than bullet journaling. I use a fairly thick journal, but it fits into a back pocket pretty easily.

                                                                        I’ve been eyeing the reMarkable since it was first announced, but their only product is still much too big for my uses. And, honestly, I don’t know whether I’d be okay with something I have to keep charged. But I also don’t like the paper waste I generate, so I guess I’m still eyeing it.

                                                                        1. 1

                                                                          An ex-coworker of mine had a reMarkable. She really loved it. I think the key feature for her was the ability to import pdf documents and mark them them up. She also liked how easy it was to organize notebooks for different contexts (as a manager, she was constantly referring to 1 over 1 notes by person, or project notes, or policy deployment notes). She didn’t seem to have issues witht he battery very often–It was a recharge it every other day sort of thing, if I recall.

                                                                          I personally prefer fancy fountain pens, otherwise I would have considered one myself.

                                                                          1. 2

                                                                            I’m a fountain pen person, myself, though I lean towards the non-fancy. Platinum Preppies are an amazing value, for example.

                                                                        2. 1

                                                                          I’m back on BUJO as well. I’ve had great success at using org-mode on more complicated projects, but my current project has few tasks, so it is easier to record my few todos in there. I don’t really bother with the calendar very much, I like the push notifications from my work calendar.

                                                                          Bonuses include being able to doodle in boring meetings.

                                                                          1. 1

                                                                            I was using a text file based checklist system that I concocted myself, but moved the todos to Todoist. Which is decent, but I find it difficult to use it for larger projects, or for recording daily activities.

                                                                            1. 1

                                                                              Do you use it the way they describe it in their intro video? Or have you made any modifications of your own?

                                                                              1. 1

                                                                                Essentially the same, though I don’t really use the monthly calendar feature. (That says more about inattention to time than about that particular feature.)

                                                                                I do use an ! notation to highlight the 1-3 things that most need to get done in a given day.

                                                                                The most important thing, I’d say, is to give the base system a try for at least six weeks (so that I you see an entire month through and more) so that you can develop an informed instinct for what you personally want to change.