Threads for llogiq

  1. 3

    My fav questions:

    What good does your company’s existence do for humanity (or the community, depends on the type of compny)? Conversely what bad outcome for humanity are you willing to accept for the financial success of the company?

    1. 1

      In the past I weeded out quite a bit of that by making it clear to the recruiter I refused to do any military/defense only projects.

    1. 5

      I’m not too fond of coding challenges. People can look at my github and see I can code at a glance. This will needlessly filter out people who are not privvy to the project, are nervous because of the interview situation, or worst of all are bad at live coding (which is unusual to do on the job).

      I usually have one question when I interview people for coding positions. I give that question out beforehand and am happy to let applicants prepare for it. The question is: What piece of code are you most proud of (Feel free to brag)?

      1. 19

        My GitHub has virtually nothing on it:

        • A toy bcrypt hash cli tool I wrote in Java 7 years ago. I haven’t programmed professionally in Java for… 7 years.
        • A Ruby gem for pretty printing tables that I literally don’t remember writing, definitely didn’t publish, and surprisingly has a README and basic tests. I have never programmed professionally in Ruby.
        • A private repo for a private guild administration mod for an MMO I used to play. Written in some truly abhorrent Lua, containing numerous bug fixes of the form “if this specific case happens, twiddle some state so wrong things don’t happen.” Almost all of these bugs could be fixed by refactoring the code into something sensible. I have only briefly programmed professionally in Lua, before rewriting the application in Go because no one else wanted to maintain a Lua/C++ project. The repo is private anyway, thankfully.

        None of these things are remotely representative of my abilities. I have significantly more skill and experience writing C++ (most of my career). I’m currently working as an SRE writing lots of bash and Terraform.

        Maybe coding challenges are bad. But GitHub is absolute garbage for gauging anything about many developers.

        1. 15

          I’m also not fond of coding challanges, but if it there has to be one, I’d much rather take one as described in these article than the contrived, shuffle-things-around-in-arrays-in-two-hours-and-hope-you-don’t-get-stuck-on-some-edge-case or make-some-service-from-scratch-and-hope-it-matches-the-tradeoffs-and-style-preferences-the-reviewer-silently-expects kind.

          1. 1

            I think your question will also have a few people who won’t like it. For example: fresh graduates who aren’t enthusiasts (proud of code?), people with wildly different experience (I’ve got 10 really lines shitty of AutoIT that keep bringing me money, probably not what you want to hear), people in jobs they can’t talk about in details (obvious). It’s a cool question for many people, but I wouldn’t want to miss out on the rest.

          1. 3

            Instead of doing this via a test, I think the idiomatic approach is to run this code in build.rs whenever the specific source file changes.

            1. 3

              Not really: idiomatically, build.rs should generate code to OUT_DIR and not to the src, and that would be quite a different pattern. But yeah, I should’ve added build.rs approach as penultimate one.

              Between build.rs writing to OUT_DIR, and test modifying src, I find that test work better, when it is feasible:

              • Generated code is human visible.
              • If this is a library, than reverse-dependencies don’t have to run build.rs (build-dependencies are contagious, while dev-dependencies are not).
              • With tests, you get more control over when the code generation is run, which is helpful when you hacking on code generation itself. More generally, build.rs is a pain to debug.
              • Kinda esoteric, but tests allow reflectiony-things – unlike build.rs, the test has access to the crate itself, so it can use types defined therein. As an example, in rust-analyzer we use the real Config type we use at runtime to generate documentation (source)

              However, if you want the output of code generation to actually not be reproducible, and instead depend on the host where the compilation is happening (this is useful, to, e.g., bind to system’s libraries), build.rs is the only way to go. That’s the core difference between two approaches: one runs code generation at build time, another at development time.

              1. 1

                control over when the code generation is run

                Yeah that makes sense. Pity that cargo doesn’t expose dev-dependencies and the crate in a more general fashion, like a scripts subdirectory.

                1. 1

                  As an aside, I always found it disagreeable that Rust assumes tests are only run during development. I can see many reasons (different platforms, different versions of dependencies, to name a few) why I as a user would want to run tests of a crate I use. But maybe I am missing something.

                  1. 3

                    Hm, I don’t think Rust assumes that? You can run tests of dependencies. For example, in rust-analyzer I can do cargo test --package num_cpus to check if that dependency works.

                    Though, to be fair, this often fails (with a nice error message) if the dependency in question have dev-dependencies. Cargo intentionally doesn’t prepare dev-dependencies of dependencies, so it can’t compile tests using those. But it doesn’t seem to be a fundamental limitation – I think it would be feasible to make cargo test --package dep for any dependency, it just needs some code and design legwork (eg, how lockfiles and transitive dev dependencies interact).

                    In practice, when I want to run tests for my dependency, I usually just checkout the dependency locally and run the tests there.

                2. 1

                  I kind of love that the build process is coupled to running tests here though.

                  1. 1

                    The downside is that build.rs has to be compiled and run before compiling your crate, thus exacerbating compile time even if the enum didn’t change.

                  1. 5

                    Nice article. The author correctly identified places that newcomers feel uneasy with in Rust:

                    • needing to always name all the trait bounds. There’s a RFC for that and I hope it gets implemented this year
                    • lifetimes are something I continuously explain. Though I still feel that the great error messages make up for any trouble you have declaring them
                    • macros may sometimes be overused. The risk of having a hammer, I guess. That said, when used with some care, you can get great results. Serde is a good example here, because the derive macros bridge arbitrary formats and data types
                    • error handling: Just have fn main() -> Result<(), Box<std::error::Error>> { .. } and use ? everywhere.
                    1. 18

                      Rust, of course, is the only language in existence which offers run-time memory safety without garbage collection.

                      I’m not sure if this holds, for instance, Swift does memory management without using a GC.

                      1. 13

                        And ATS, which provides the ability to do pointer arithmetic and dereferencing safely without garbage collection. In general, claims of “only one that does” and “first to do” should be avoided.

                        1. 5

                          ATS is the first language to have a “t@ype” keyword.

                          1. 3

                            ATS is very interesting! thanks for sharing it

                            1. 2

                              Check out Aditya Siram’s “A (Not So Gentle) Introduction To Systems Programming In ATS,” it’s a great overview.

                          2. 11

                            It depends a bit on how you define garbage collection. I’ve seen it used to mean both any form of memory management that does not have explicit deallocation or specifically tracing-based approaches. Swift inherits Objective-C’s memory management model, which uses reference counting with explicit cycle detection. Rust uses unique ownership. C++ provides manual memory management, reference counting, and unique ownership.

                            1. 6

                              Rust uses unique ownership. C++ provides manual memory management, reference counting, and unique ownership.

                              Both Rust and C++ provide all three.

                              1. 4

                                The problem is that C++ can also provide stuff you don’t want in your code usually - without using an unsafe {}.

                            2. 5

                              Ada meets that definition, too.

                              Even modern C++ could claim to have run-time memory safety without GC, but that obviously requires the developer to use it correctly.

                              1. 5

                                Ada isn’t completely memory safe, though I would say it’s a lot safer than C or C++ with all of the additional built-in error checking semantics it provides (array bounds checks, pre/post conditions, numeric ranges, lightweight semantically different (derived) numeric types, type predicates). I’ve found it hard to write bugs in general in Ada-only code. It’s definitely worth checking out if you haven’t.

                                As for modern C++, it feels like we made these great strides forward in safety only for coroutines to make it easy to add a lot of silent problems to our code. They’re super cool, but it has been a problem area for myself.

                                1. 3

                                  Rust is also not completely memory safe: it has an unsafe escape hatch and core abstractions in the standard library as well as third-party frameworks require it.

                                  1. 2

                                    I agree. Not a lot of people are familiar with Ada, so my point was to dispel the myth it is completely safe, while also answering the common reply I’ve seen that “Ada isn’t memory safe, hence you shouldn’t use it.”

                              2. 3

                                Isn’t atomic reference counting a form of GC as well?

                                1. 4

                                  One could say that everything that deviates from manual memory management is some form of GC. Still, we do have the traditional idea that, generically speaking, GC implies a background process that deallocates the objects asynchronously at runtime.

                                  1. 3

                                    If you think about it, stacks are GC because they automatically allocate and deallocate in function calls. 🤔 That’s why they were called “auto” variables in early C.

                                    Galaxy brain: malloc is GC because it manages which parts of the heap are free or not. 🤯

                                    1. 1

                                      ahahah great viewpoints, wow I learned so much with your comment, it got me looking into “auto” C variables. never realised that all vars in C are implicitly auto because of the behaviour that they get removed when they go out of scope 🤯 (I wonder how did they got explicitly removed back then? and how it all relates to alloca()? could it have been designed that way to allow for multiple stacks at the same time with other segments besides the stack segment?)

                                      that last bit about malloc is amazing, it is indeed managing virtual memory, it is us who make the leaks 😂

                                      1. 1

                                        all vars in C are implicitly auto because of the behaviour that they get removed when they go out of scope 🤯 (I wonder how did they got explicitly removed back then?

                                        Back in the day, as I understand it, there was no “going out of scope” for C. All the variables used by a function had to be declared at the very top of the function so the compiler could reserve enough stack space before getting to any code. They only got removed when you popped the stack.

                              1. 2

                                Hmm, helpful, but perhaps not as helpful as it could be.

                                • “Linked lists” could be better described as “cyclic data structures”. For most graph algorithms I’ve seen the adjacency-list representation is more convenient anyway, so I tend to find graphs represented as nodes and pointers to be something of a white elephant. I’m far from an expert though.
                                • Self-referencing data structures are now possible with Pin, though reading the docs there still are probably enough to convince anyone that they don’t want want a self-referential data structure after all.
                                • The main reason not to have global mutable state, besides the sanity of the person who has to read the code later, is thread safety. They talk about mutexes and such but never say “global mutable state becomes unsafe once you have threads”.

                                All in all a good post though. As for initializing an array without re-initializing it, I had to give it a go and see what happened. The results were, hilariously at once more and less than I could hope.

                                1. 3
                                  • True, the problem with doubly linked lists (as well as other cyclic data structures) is indeed the ownership being muddled.
                                  • Yes, you can build self-referential data using pin, but why do it by hand when you can use a macro?
                                  • Regarding global mutable state, I have a // I solemny swear that I'm up to no good, and also single threaded. comment in the code example, but perhaps that was too easy to miss.
                                1. 5

                                  Thanks for sharing, here! I like this approach to trying to learn Rust, because there are a handful of patterns in other languages that aren’t feasible in Rust

                                  1. 2

                                    Glad you like it. And yes, Rust chooses some tradeoffs differently than other languages, which sometimes trips up people new to the language.

                                  1. 8

                                    Knowing these impossible cases is quite useful — it can save you from fighting with the borrow checker a battle that you can’t win.

                                    1. 5

                                      Well, not exactly impossible, just needs a bit of unsafe and – Oh god why are there dolphins swimming in my pretzel bath (undefined behavior)?

                                    1. 11

                                      This is a helpful article for me, thank you for posting!

                                      Does Lobsters allow posts like these, though? It’s a great article, but includes an ad for a service as the last section.

                                      1. 9

                                        It’s a useful article until then so it’s worth letting the votes govern its relevance, imo.

                                        1. 6

                                          I’d say there’s a difference between “here’s some useful Rust stuff, btw use our logging SaaS at the end” and “here’s why you should use our logging SaaS”

                                          1. 5

                                            Author here, glad you like it.

                                            I will add a conclusive sentence to make the distinction between the article and the advertisement clearer.

                                            1. 1

                                              Thanks for the article, I didn’t mind the ad. Do you inspect the stack frames non-intrusively via sampling?

                                            2. 4

                                              if it’s not too intrusive its okay, for example when you can read the article without the ad and you don’t miss big parts of the post

                                              1. 3

                                                Personally, I don’t mind it. There’s a lot of great and interesting content out there published by companies that usually includes some sort of “ad” for their service. I don’t want to cut that out just because they say, “hey, use our stuff” at the end. Especially because I can just ignore the ad bit and still learn something.

                                              1. 1

                                                This is a blast from the past. Seeing my old 2016 quote in the introduction brought up some memories. Also the fireflowers blogstravaganza has a longer version of that quote.

                                                1. 13

                                                  mrustc can compile Rust to C. So it doesn’t depend on LLVM (with some caveats). Also fuzzing cannot match static guarantees. The former is: “I did a search through all code paths I could find and didn’t find a bug”, whereas the latter is “there may be no bug, no matter what code path is taken”.

                                                  Case in point: I once had a bug in a string handling library that was extensively fuzzed, but all that fuzzing didn’t find the UTF-8 short space character that led to a byte index landing within a UTF8 character.

                                                  1. 2

                                                    Would it ever be possible or desired for a variable to check for common traits as a secondary option when the types of the branches of its assignment don’t match up? In this case, inferring impl Read for that variable in your example.

                                                    I suspect this is not a desired feature primarily because it would lead to some very confusing errors and behavior, but it also seems more correct than having to go through an initial, superficially superfluous, binding process.

                                                    1. 1

                                                      Esteban Kuber already told me that there’s some logic in the Rust compiler that will lead to nicer error messages in some cases already; just the (quite special) case I was showing in my blog wasn’t covered yet.

                                                      1. 4

                                                        Yeah, this is the first solution people reach for, and as far as I can see, the docs steer you in that direction, so don’t blame yourself.

                                                        1. 9

                                                          Author here. With this post, I wanted to dispel the notion that an expert by definition knows everything. Also Rust’s pace of change can be quite enjoyable, because for the most part new changes make things easier, more powerful or both.

                                                          1. 28

                                                            When I read “time safety”, I mentally prepared for a discussion of timing attacks, which some libraries available in both C and Rust can harden potentially affected code against. But no! This was the “young languages not going to survive” angle.

                                                            So let me offer a prophesy: Rust is here to stay. Yes, there will be other languages that may offer even more enticing tradeoffs (one should hope), but just as C will survive competition from Rust, Rust will survive competition from those new languages.

                                                            1. 11

                                                              I thought the author meant spatial/temporal safety. Papers on the topic talk about memory (eg buffer overruns) and spatial (eg use-after-frees). Then, there’s time-related attacks like time-of-check to time-of-use attacks, timing channels, etc. The phrase @Hales was looking for is software longevity.

                                                              1. 5

                                                                I think most of us has the same thought(s).

                                                              2. 6

                                                                Slack happened to publish a post about adoption of new technologies that is sort of interesting on this front.

                                                                I think Rust and Go (and some other newish langs like TypeScript) fill niches that will give them an active community for a good while, but even if we assume they go out of fashion and stop growing, there is more than enough code already written in them to economically justify companies keeping them maintained a long time. That seems like more or less how older langs got established, too.

                                                                If you need examples, Docker, Kubernetes, and a ton of internal code at Google, CloudFlare, etc. are in Go, and Firefox and various companies’ critical infra depends on Rust. Rust also benefits from the yet-more-established LLVM project handling a lot of lower-level bits.

                                                                For comparison, in the early 2000’s there was incredible hype around XML and fancy object models like COM. They turned out not to be the future: HTML evolved into HTML5 instead of XHTML; REST and JSON ended up a more popular base for APIs than XML-RPC or SOAP; and Mozilla ended up removing a lot of XPCOM use from Gecko. But you can still use XML, SOAP, or COM! And, for that matter, Fortran, Lisp, and awk! Putting down enough roots to ensure a technology’s long-term survival is different from the tech remaining super popular forever.

                                                                I can’t learn everything that’s coming out, but I do find today’s diversity of languages and compilers heartening. A couple decades back it felt like programming was kind of “stuck” because a decent compiler was a huge project and network effects made only a few languages and platforms viable. I think a lot of things have come together to change that, which is great, since we collectively learn by experimentation.

                                                                1. 1

                                                                  Another way of looking at it is generational. How many people are learning C vs C++ vs Rust? I’m prepared to go out on a limb and say the next generation of “non-GC” language users will be a predominantly Rust crowd. That’s the generation that will be writing new software.

                                                                  Niche language changes happen all the time, look at the death of Perl in favor of Python. PHP to NodeJS. Now: C/C++ to Rust.

                                                                  1. 3

                                                                    This does not account for the young folks currently learning and using C or C++. Or for the Perl coders currently working in banks. PHP is alive and well, too. Sure, there are certain shifts happening, but the death of all of those technologies has been greatly exaggerated.

                                                                1. 4

                                                                  Haven’t we all read this rant a thousand times before (though perhaps with different wording)? However, I feel the author got a few things wrong:

                                                                  1. Erlang gains its famed robustness not by its OOP implementation, but by its solid VM and the crash-only principle (working even in the face of errors)
                                                                  2. Functional programming is not the solution, it’s overshooting in the other direction. The problem with procedural and OOP programming is shared mutable state, not any mutable state. I personally think that Rust offers a very good solution that gives us much of the benefits of functional programming, but much less of the cost.
                                                                  1. 2

                                                                    We already have a few security-relevant clippy lints, and there’s work to increase their numbers. Personally I feel that this approach is severly undervalued, because while it may not find all issues, it finds a lot of them at very modest cost.

                                                                    1. 2

                                                                      One factor for the wordiness of Rust implementations is that they often have to repeat stuff because the benchmarksgame maintainer does not admit solutions containing macros in Rust. Idiomatic code would usually be shorter.

                                                                      1. 11

                                                                        Well, it’s actually more borrowing than stealing, and Rust is pretty much into that. :-)

                                                                        1. 2

                                                                          One thing that is curiously absent from the discussion is dependency management. This may seem trivial but is full of interesting edge cases, e.g. multiple versions of a dependency, to which current state of the art has not yet appeared to find an optimal solution.

                                                                          1. 1

                                                                            Those are discussed in this comment:

                                                                            https://lobste.rs/s/cd5lk4/low_hanging_fruit_programming_language#c_8y9bpu - 3rd bullet point.

                                                                            Or am I misunderstanding you?