1. 14

    “Congressman, I don’t have all the answers to your very technical questions…”

    That’s not something you hear everyday. Who is this Riggleman guy?

    1. 7
      1. 2

        It’s interesting because he sounds decently familiar with GitHub. I wonder how many Congresspersons have GitHub accounts, if any?

        1. 5

          Perhaps your expectations of congressman is so low that the ability and initiative to use a website to do research is the more surprising part, because it doesn’t take a lot of familiarity with Github to perform a search. He did sound familiar with programming on more than a surface level, however.

          1. 7

            He was able to talk confidently about nightly toolchain builds though, which takes a fair amount of technical understanding.

            1. 12

              His mention of DoD practice leads me to think he picked this up as an intelligence officer. You don’t have to be an experienced developer to recognize high-level risks. Extrapolating from a single point of experience working for a former I.O. for several years, they have a keen skill for picking through details.

              1. 1

                He was also an NSA contractor.

                1. 1

                  I think he did indeed mention he had a background in intelligence.

              2. 4

                What jgb said. He talked like a programmer or project manager, not someone vaguely familiar with it.

                1. -5

                  It’s not so much low expectations it’s just the average age of a congressperson is 57, so it’s kind of new to see folks who would be familiar with something like Git.

                  1. 29

                    About half my computer science lecturers at university were older than that, and they were all familiar with git. My dad’s about that age, and he’s familiar with git.

                    57 isn’t actually particularly old. Many of the pioneers of computer science have died of old age at this point. We’re well past the point where programming or computer science is a ‘young man’s game’ in any reasonable sense.

                    1. 5

                      The number of programmers doubled roughly every 5 years for a long period of time. Possibly from the beginning up until recently. This suggests that there are 64 times more 25 years old programmers than there are 55 years old programmers. Yes, all the pioneers are now old. But they were exactly that: few pioneers.

                      Programming has never been a young man’s game, but this exponential growth skews the numbers like crazy, and make it appear like a young man’s game. After all, if the only thing you know about someone is their age, the older they are, the less likely they are to have learned programming.

                      1. 2

                        there was definitely a dip in the rate of CS enrollment after the dotcom bust in 2000, but then numbers of both major and nonmajor CS exposure has seen a massive surge since 2005

                        1. 1

                          Very well explained, thank you!

                        2. 8

                          Linus Torvalds himself turns 50 this year.

                          1. 4

                            57 and working in computer science is different from the average 57 year old who may not have an in-depth exposure to computer science.

                            1. 20

                              I wouldn’t expect that the average 57 year old has a better or worse idea of git than the average 21 year old. People often claim that young people are better with technology. In my experience, they tend to not be at all.

                              1. 4

                                In my experience, they tend to not be at all.

                                Young people work for cheap and are more easily taken advantage of.

                                Why do you think so much of advertising is aimed at people in their twenties? Some disposable income and not as much life experience.

                                1. 3

                                  Yeah, the average 21 year old also has no exposure to computer science either. I agree it’s a pointless comparison.

                              2. 2

                                Good point! My bias is showing (growing up where I did, the only people I knew who knew about computers were my age). This makes me hopeful that I can still be programming well into retirement age :)

                        3. -1

                          Yuck

                          1. 1

                            I agree that his tie isn’t the most flattering, but I wouldn’t necessarily say “Yuck”.

                            Care to elaborate?

                            1. 1

                              Lol I didn’t notice the tie. Purely a political yuck. He’s proud of bombing Afghanistan, pro-trump tax cuts, pro-deregulation, and anti-gun control. ¯_(ツ)_/¯ to whether his staffer gave him talking points on rust and javascript.

                      1. 10

                        I have had the view that safety is typically not the most important goal of a project (user satisfaction is). In my experience, safety can get in the way of writing software that is useful (the real world is really messy). It’s great to see a real-life case with Rust from someone who obviously tried very hard but ultimately had safety get in the way of writing the software they wanted. Hopefully, Rust will evolve to interface with the “unsafe” world in a more ergonomic way.

                        1. 9

                          I think many people obsess over Rust’s idea of safety and lose track of the point of safety. The point of safety is to create software that does not leak (performance or memory) and does not crash.

                          It is entirely possible to write software that does not leak or crash, in C. It requires good practice and good tooling to enforce that good practice, as does programming in literally any other programming language (You can write spaghetti code in any language, after all).

                          1. 6

                            That’s absolutely true, but how much faith do you have that Way Cooler will be one of the C projects that uses good practice and good tooling to minimize the amount of memory-safety bugs?

                            1. 1

                              If it’s written by somebody that is very familiar with Rust (and clearly it will be) then actually I have a lot of confidence in Rust. Writing a lot of Rust is like writing a lot of any language: it infects your mind and way of doing things, and I suspect it will have infected the author’s mind with thinking about memory management constantly, which will hopefully mean they think about it constantly during their C programming too.

                              1. 1

                                This has actually happened to me, the more I write Rust the more I can predict what the compiler will complain about. And I think about that a lot when writing C too. It’s very… interesting? when I’m writing C and I think about ownership.

                            2. 4

                              I actually think a more encompassing tool that also deals with safety, but not just safety, all other forms of bugs is Design by Contract. I’m excited to see DbC will be part of the C++ language standard for 2020. Rust had a discussion about DbC as part of the language but many feel this library fills most of the needs. While a library approach is better than nothing, having DbC as part of the language (after all, types ARE a contract) makes more sense to me. Hopefully, the Rust folks keep the discussion going and make DbC part of the language. Maybe more discussion happened but I haven’t seen it.

                              1. 3

                                Out of curiosity, how is Design by Contract different/better than just sprinkling assertions at the start/end of your functions? Most of the examples I’ve seen for it are like those in the readme of the library you linked, which are fairly trivial. How do you express more complicated contracts like, say, “The sublist returned by this list search routine is a subset of the list passed in and shares the same memory”? Do you have suggestions for more in depth things I can read?

                                1. 3

                                  Most languages don’t have first-class support for Design by Contract so most implementations are glorified assertions. To express more complicated contracts you would use higher level functions in your assertion. For example, you can define a “is_subset” function and use that in your assertions.

                                  I do many C++ projects and use DbC for all of them, and before C++2020 I used a small library I wrote Which I copy and past in all projects. When compilers will support native contracts in C++, I’ll use those instead of the library.

                                  1. 2

                                    My Dafny is a little rusty, but assuming you mean modifying the list to get the sublist, it would be something like

                                    modifies array
                                    ensures exists lo, hi :: out == old(array[lo..hi])
                                    
                                2. 3

                                  How about memory vulnerabilities leading to RCEs? Do you suggest apps with those are safe? Why “has leaks” is unsafe, but “has remote code execution vuln” is safe? I totally don’t get it. Can you explain, other than just claiming “because I say so”?

                                  1. 1

                                    Can you explain your position better?

                                    Are you saying that GCC is guaranteed to generate code that has remote code execution vulnerabilities? And Rust doesn’t have this?

                                    It’s my understanding that memory leaks are what cause RCEs (At least, the main cause of them). It is also my understanding that there is nothing inherent about C’s memory model that causes presumably safe (As tested by tooling and humans) code to magically appear with RCEs.

                                    1. 4

                                      RCEs are not caused by memory leaks, but most commonly by accidental occurences of:

                                      • use after free (this is something different than memory leaks — more like opposite of memory leaks: mem leak is when you forget to free(), use after free is when you do free() and yet dereference the pointer afterwards)
                                      • out-of-bounds array reads/writes (most notoriously as a result of off-by-one errors, but not only)
                                      • Undefined Behavior (good intro: [1] [2] [3])

                                      Especially the much-too-many, casually unknown UB “fine print” cases are “something inherent about C that causes presumably safe (as tested by tooling and humans) code to magically appear with RCEs”. The most infamous example that basically proves that human/tooling testing is not enough, is the recent RCE in SQLite, a project that is often perceived as the most covered by tests & tooling & “human review” open-source C codebase in the world, with any contenders being far behind. Other than that, the PVS-Studio’s website is a great reference showcasing the proliferation of (often RCE-grade) errors in widely used open-source C codebases. (The common understanding being, that closed-source codebases are usually even worse.) Their blog is also worth a read.

                                      Rust is specifically designed with an aim towards completely eliminating whole classes of such errors. Not all errors, mind you. But especially the RCE-grade ones resulting from the reasons I listed above. IOW, yes, I’m saying that GCC/Clang is guaranteed* to generate code that has remote code execution vulnerabilities, and Rust doesn’t have this**.

                                      * — Unless: (a) maybe if the codebase were written by 1 person, who is flawless; but there is no such person; (b) also, there’s some chance military-grade hardened C code might have no RCEs (this requires super expensive and tedious dev process); (c) code written in Frama-C or similar “verified C” dialects, potentially.
                                      ** — You can still write RCEs in Rust, but it’s levels of magnitude harder to do accidentally, and close to impossible if you’re not using unsafe blocks (barring bugs in the compiler/standard library).

                                      Edit: Also, please note that I’m fully aware Rust is super annoying to work with. I myself tried, and gave up for now. I’m not claiming it’s a panaceum for any and all problems. But C, and esp. C++, those are paths I followed with devotion, deep enough that I touched the lurking madness, and came back shaken and changed forever.

                                      1. 2

                                        The supposed RCE in sqllite is dubious. Sqlite is a database that can accept executable code as an input. If your application allows unrestricted access to that database and someone then provides an input to the DB with executable code in it and the DB executes it, then the error is in the application, not the DB.

                                        1. 3

                                          If you let a user write queries, it’s expected behavior that they can modify the database.

                                          It’s not expected behavior that they can read/write unrelated files or perform network activity.

                                          1. 2

                                            that is exactly the intended functionality of the sqlite full text search

                                            1. 1

                                              Did you somehow reply to the wrong comment?

                                              How is full text search intended to let me overwrite /etc/passwd?

                                              The text search index is stored in the same database file as everything else. I expect users with access to use it to read/write that file.

                                          2. 2

                                            Sorry, but it feels like “blame the victim” mentality to me. Did SQLite at least come with warnings of “do not let users write SQL queries, as we don’t audit such scenarios for security”?

                                            1. 2

                                              It’s not at all “blame the victim”. It is: “understand what the tool does”. SQLite doesn’t even have user accounts. It’s an SQL engine and SQL is a powerful language.

                                          3. 0

                                            use after free (this is something different than memory leaks — more like opposite of memory leaks: mem leak is when you forget to free(), use after free is when you do free() and yet dereference the pointer afterwards)

                                            This is a simple error to avoid, though. Alter free() to check for NULL and don’t free() if the input is NULL (Something that is nonsensical and a check that should be done anyway), then after every single free, set the pointer to NULL. It becomes very, very difficult to use-after-free using this method. In the same way, set file descriptors to negative values before assignment and check for negative values before close(), etc.

                                            out-of-bounds array reads/writes (most notoriously as a result of off-by-one errors, but not only)

                                            Every single array should store and check against the maximum number of elements, and in some cases the current number of elements in the array.

                                            Undefined Behavior (good intro: [1] [2] [3])

                                            This is probably the only case that causes errors. However, there are tools to check for UB (One of them, PVS-Studio, you linked to. Another is available here: http://css.csail.mit.edu/stack/). It is possible to remove the UB from C, but there is a lot of resistance to it for the reason that it is useful. I personally don’t agree entirely with them, and I do not see the need to rehash those arguments here.

                                            Formal verification is something I find deeply interesting, but at some point you need to balance ‘shipping’ against ‘total safety’. I also don’t see distrusting {GCC / Clang}’s code generation as a ‘useful’ stance, given that most ‘safe’ languages eventually, somewhere down the chain, rely on the code generation from {GCC / Clang}. A case in point, Rust’s first version was written in OCaml, which descends from OCaml Light, which was written in C.

                                            If you truly believe that “GCC/Clang is guaranteed to generate code that has remote code execution vulnerabilities” (Emphasis mine), then you must extend that distrust to the OCaml Light code generator, which was generated by {Clang/GCC}, which means you have to distrust OCaml (A language cannot be safe without safe code generation), and therefore you can hardly trust Rust to be safe!

                                            1. 2

                                              Ok, from what you wrote here, I am surprised to see that we seem to be kinda coming to an agreement. Meaning, theoretically, I certainly agree, that it’s possible to have safe code emitted from GCC, iff the input C source code is perfectly flawless (as I explained in the footnote). I stand by my claim however, that in real life, i.e. practically, this cannot really be achieved (with the exceptions I stated previously). Moreover, I suppose even PVS-Studio is not perfect; I don’t know it very well, I admit, so maybe I’m in error, but I’d be really (and positively!) surprised if they claimed to eliminate all UB-based errors.

                                              Interestingly, as to generated C code (i.e. output of compilers such as OCaml Light, Nim, etc.), I believe it can be actually much easier to keep safe! The trick here is that the generated C code will probably be a relatively small/finite subset of predesigned C patterns/snippets. The author of the compiler should thus be able to enforce using only safe C constructs; interactions between the limited number of patterns can be scrutinized much better; and finally, extra protections such as bounds checks can be added fully automatically to every snippet that needs them, leaving no space for an occasional human error in perusing them. (Including the common hubris such as not setting a freed pointer to NULL “because obviously it won’t be used anywhere further, so why waste the coveted CPU cycles”.) OTOH, if a compiler author does introduce some UB, I imagine there would be a higher chance that it will get repeated automatically by the compiler, thus hopefully making it “louder”/more frequent and therefore easier to notice and fix.

                                              Edit: Also, please note, that with all the checks you suggest (in free, in arrays), you’re actually already not talking about basic C, but some special dialect of C-with-protections! Notably, some of them (e.g. bounds checks) are often laughed away by C programmers, as “costly, reducing effectiveness/speed”. And with this notion of adding reasonable protections, you can slowly get to trying to unknowingly reimplement Rust! Or Ada, more probably. Which is indeed seen as much sager language than C. (Though also more annoying, I believe even than Rust.)

                                              1. 1

                                                you’re actually already not talking about basic C, but some special dialect of C-with-protections!

                                                Wow, I didn’t realise that coding properly was called coding in a different language! Thanks! I didn’t realise that ‘Python with style-guides and tooling’ was a different language to Python! That’s amazing! /s

                                                The trick here is that the generated C code will probably be a relatively small/finite subset of predesigned C patterns/snippets. The author of the compiler should thus be able to enforce using only safe C constructs; interactions between the limited number of patterns can be scrutinized much better; and finally, extra protections such as bounds checks can be added fully automatically to every snippet that needs them, leaving no space for an occasional human error in perusing them.

                                                So what you’re essentially saying is that, you can code safely in C, albeit extremely carefully. Yes, we do seem to be agreeing.

                                              2. 1

                                                This is a simple error to avoid, though. Alter free() to check for NULL and don’t free() if the input is NULL

                                                That only works if they’re not only freeing the same spot in memory, but also freeing it through the same pointer. That’s not where most of the use-after-frees come from. The use-after-frees all come from aliased pointers, like in this code.

                                                void consume_object(object *ptr) {
                                                    do_something_with(ptr);
                                                    free(ptr);
                                                    ptr = NULL;
                                                }
                                                void main_whatever() {
                                                    object *ptr = malloc(sizeof(object));
                                                    init_object(ptr);
                                                    consume_object(ptr);
                                                    /* ptr is not NULL, in spite of what `consume_pointer` did, because reasons */
                                                    free(ptr);
                                                    ptr = NULL;
                                                }
                                                
                                                1. 1

                                                  because reasons

                                                  But if you’re writing code like that, you don’t understand pointers or argument passing. If I write code in Haskell and expect it to be strict-evaluation, then there will be huge problems with it. That’s not a fault of the language. That’s a fault of me.

                                                  Besides, as I have previously said, these problems are caught with appropriate tooling. Both cppcheck and scan-build point out this error.

                                                2. 1

                                                  Alter free() to check for NULL and don’t free() if the input is NULL (Something that is nonsensical and a check that should be done anyway),

                                                  Two problems:

                                                  1. Developers regularly don’t do it enough to catch everything.

                                                  2. There might be a performance penalty.

                                                  Rust’s method increases odds they’ll have to deal with it while eliminating the need for runtime checks. If runtime checks are fine, there’s way to do those, too, while getting other benefits for memory safety.

                                          4. 2

                                            “It is entirely possible to write software that does not leak or crash, in C.”

                                            It will be a lot harder in most cases. Especially given memory safety applies on all inputs. Getting that in C usually means hand-inserting checks everywhere and/or running it through a sound static analyzer that might cost five digits.

                                            “ It requires good practice and good tooling to enforce that good practice, as does programming in literally any other programming language (You can write spaghetti code in any language, after all).”

                                            This is a false equivalence. If the code is safe Rust, your mistakes will not usually lead to code injection. Programmers will make mistakes, esp if overly casual or hurried. Field evidence indicates most will do this regularly with careful experts doing it some of the time. In C, those mistakes will increase number of successful hacks or leaks.

                                            So, you could say using something that converts most hacks into panics is using “good tooling” to get good results. Aside from borrow checker, you get most of that safety without even trying. That boosts productivity on that kind of code. If borrow checker is too much, one can downgrade to reference counting or unsafe with the other risks still mitigated automatically.

                                            1. 1

                                              Getting that in C usually means hand-inserting checks everywhere and/or running it through a sound static analyzer that might cost five digits.

                                              From personal experience, a lot of the tooling that helps you avoid these mistakes is free. But, don’t let that stop your fearmongering, please.

                                              If the code is safe Rust, your mistakes will not usually lead to code injection.

                                              [citation needed].

                                              No, really. As far as I know, there are no long-term studies on Rust projects. I don’t think you can argue with ‘field evidence’ until you can show that ‘field evidence’ proves that Rust improves safety. After all, as you say, programmers are lazy. For all you know, they could just be doing the equivalent of dumping unsafe { ... } everywhere the borrow checker complains and calling it a day.

                                              1. 1

                                                a lot of the tooling that helps you avoid these mistakes is free.

                                                Are the tools for total memory safety in C as easy as a Rust compile offering same guarantees? Especially no temporal errors or races on all inputs?

                                                It’s a trick question: I’ve submitted more tooling like that here than anybody. I read their performance and effectiveness evaluation sections. It usually takes more CPU/RAM with less certain benefits than just using Rust. Then, we have the constant vulnerabilities supporting my position. Amateurs are doing better in Rust so far since it’s just immune to a lot of those problems. The compiler yells at them and/or apps just panic in bad situation.

                                                “I don’t think you can argue with ‘field evidence’ until you can show that ‘field evidence’ proves that Rust improves safety. “

                                                The design of the language makes it immune to many classes of errors. Outside a compiler error, about any code in safe Rust will inherit those properties. If you’re talking compiler errors, that would be weird since C compilers, esp optimizing, have been buggy as hell without C programmers showing up dismissing potential benefits of C until their compilers are proven correct. Virtually no use of CompCert in GPL’d software either. Be a double standard there.

                                                “For all you know, they could just be doing the equivalent of dumping unsafe { … } everywhere the borrow checker complains and calling it a day.”

                                                Btw, the borrow checker is just one of many safety mechanisms in Rust. It covers temporal errors that show up even in OpenBSD. I mean, if they can’t avoid them…

                                                What you say might be true, is worth looking for in field data, and might give a different picture of average app in safety. That said, even if they were doing that, the code would still be safer than C given it has no protections against those same risks vs Rust apps likely combining pre-existing, borrow-checked libraries with new code, some of which is unsafe. Attack surface gets lowered just because the lazy path in Rust is pre-existing, safe libraries. The harder path, creating borrow-checked code, is strongly encouraged by its ecosystem to get code into stdlib’s, etc. Better default than C again.

                                        1. 6

                                          I think I noted it elsewhere at some point, but I believe that aggressive spam policies of the kind “you’re spam if you’re not a large provider” are illegal towards small mail providers and could be legally charged, at least in Germany under UWG (German competition law). A small e-mail company would have to test this out in court, though.

                                          1. 1

                                            I’ve discussed this with the Czech anti-trust body but they believe that since customers can always use another email provider if they want to communicate with us and since Google does not have large enough market share (except our client DB says over 40% just GMail) that there is only a small chance to fine them.

                                            But I have not yet filed the official complaint.

                                            1. 2

                                              they believe that since customers can always use another email provider if they want to communicate with us

                                              But they literally can’t, that’s the whole point. If they do, their mail gets swallowed by gmail…

                                              1. 1

                                                Google has only about 20% of Czech email market share and about 40% among young people. Everyone can use Seznam (@post.cz, @email.cz) instead. Google won’t ignore largest Czech provider. Sigh.

                                                We have run our own mail server for at least two decades.

                                          1. 4

                                            We must suggest books, blogs, videos, encourage colleagues to attend meetups, conferences, and workshops.

                                            Part of the reason that people don’t want to spend money on mentoring etc. is that this image has been created that development of your skills and knowledge must take the form of meetups, conferences and workshops. That couldn’t be farther from the truth. The best way to get better at something is to do it, to practice it, to solve problems using your skill and learn lessons from how you went wrong and how you went right.

                                            The point of those interviewing processes is not to hire people with the best superficial knowledge but the smart, decent, hardworking people. They’re big and overcomplicated precisely so that you can find a justifiable reason to hire anyone and to not hire anyone, because the hiring is clearly not being done based on those reasons, it’s being done on a ‘I like this person and want to work with them’ vs ‘I don’t like this person and don’t want to work with them’ basis. I’d bet any day that the majority of people hiring programmers would rather have someone that needed a bit of training in the problem domain but was a decent, hard working, interesting, polite, friendly person vs someone that knew the problem domain inside out but was a prick. But from what I’ve heard, not hiring someone ‘because he or she is a prick’ opens you up to being sued in the US, so people create ridiculous interviewing processes so they can always find a reason to hire or not hire anyone.

                                            1. 1

                                              I think meetups, blogs, videos and the like are important in terms of finding ideas to try out and making sure you’re not too insulated in your approach to the trade. But I think it’s equally important to put said ideas into practice, and the workplace is the most available place for most of that.

                                            1. 17

                                              However, it also defines operator* and operator->. These methods also provide access to the underlying T, however they do not check if the optional actually contains a value or not.

                                              Wat?

                                              1. 15

                                                Using operator* or operator-> on an optional that doesn’t contain a value is undefined behavior, see: spec, cppreference

                                                I’ve been about to migrate a bunch of APIs from std::unique_ptr<T> to std::optional<T> and now I’m really not feeling as great about that plan.

                                                1. 19

                                                  On the face of it this seems like an insanely bad API design decision by the committee.

                                                  1. 5

                                                    What should it do? Throwing exceptions would make the API useless to many large consumers. Default-constructing the value type would probably be worse. The C++ type system just isn’t very good.

                                                    1. 25

                                                      What should it do?

                                                      not offering those operators at all and instead forcing the usage of map, flatmap or get_or_default like most languages do.

                                                      We opensourced a library that implements a more functional API here

                                                      1. 2

                                                        What should it do?

                                                        not offering those operators at all and instead forcing the usage of map, flatmap or get_or_default like most languages do.

                                                        That’s unacceptable when you know the optional has a value and performance is critical. Nothing is stopping you from implementing “get_or_default” on top of the operations provided, but you cannot implement operator* as it currently is on top of “get_or_default”

                                                        1. 4

                                                          That’s unacceptable when you know the optional has a value and performance is critical.

                                                          C++ is a zero cost abstraction language and lambdas get inlined. Unless the optional is implemented via a vtable, you should not see any overhead.

                                                          1. you might be right today but what about tomorrow? - will your assumption still be true if someone else will modify some (distant) part of the codebase?

                                                          2. If you know that an optional will always contain a value, why is it in an optional in the first place?

                                                          Nothing is stopping you from implementing “get_or_default” on top of the operations provided, but you cannot implement operator* as it currently is on top of “get_or_default”

                                                          Well the argument is operator* you should not exist as it eventually leads to unsafe code and bugs. You may always know when you can get away of using operator* without prior checks and may not need such construct but most people get it wrong at least once.

                                                          If you work in a team you will realize those unsafe usages become a liability as they are prone to break due to distant changes. As a result this is not very social: this practice pushes the responsibility of debugging or verifying your assumptions to everyone who is contributing to the codebase. Every Time someone works on a feature and coincidentally breaks the unsafe code will also need to fix it up; it becomes his responsibility.

                                                          Lastly, just for the sake of argument: In case your optional implementation does not include a footgun, this is how you could build one:

                                                          T const& optional<T>::operator*()const {
                                                             return this->get_or_default(*(T*)nullptr);  // that's fine it's just undefined behaviour 
                                                          }
                                                          
                                                          1. 2

                                                            You shouldn’t be forced to check if the option is filled each time you access it. One check is enough, then you can assert that the option is filled in all following code paths. If you don’t want to do that, force your team to always use “get_or_default” but don’t force the world to work like your team, not everyone has your performance constraints.

                                                            1. 1

                                                              You shouldn’t be forced to check if the option is filled each time you access it.

                                                              You only test once. If you are worried that running map or get_or_default test for the content multiple times, don’t worry, the compiler will optimize it away: https://godbolt.org/z/7RGUCf

                                                              1. 1

                                                                That’s not true in all cases.

                                                          2. 2

                                                            If you know a value exists and performance is critical …why are you using std::optional in the first place?

                                                            By this logic, you might as well demand that std::map should have implemented operator[] not to take const Key& key but instead an already hashed bucket identifier, and if there’s nothing in that bucket, or not what you were expecting, oh well, have some undefined behaviour?

                                                            It’s silly. If you don’t want the overhead of a particular container, don’t use that container.

                                                            Insisting that std::optional container has to have a hole in it … either you want an Option or you want a raw pointer. “I want an Option but it has to behave exactly like a bare pointer” is an incoherent position for an API trying to satisfy everyone and ending with something useful to no one. “It’s safe as long as you always 100% without fail manually check it before dereferencing, otherwise undefined behaviour” adds nothing that wasn’t already available.

                                                            1. 2

                                                              If you know a value exists and performance is critical …why are you using std::optional in the first place?

                                                              What if you already checked it once? Why should you be forced to check each time you access the contained value?

                                                              Insisting that std::optional container has to have a hole in it … either you want an Option or you want a raw pointer.

                                                              It’s not a raw pointer, it’s a boolean paired with a value. There’s no necessary indirection.

                                                              1. 2

                                                                What if you already checked it once? Why should you be forced to check each time you access the contained value.

                                                                Then extract the value the first time? Why would you design an entire API around “people might unnecessarily check for whether some value is present multiple times”? Leave Nones at the edges of your program. Once you’ve determined that there is Some(x), everything else should be dealing with x, not the Option it started in.

                                                                The question, if anything, illustrates exactly why these are bad operators to have in the API.

                                                                Without them, Options are cumbersome enough that you very quickly realize slinging them around in the core of your program is silly; you extract the present value, substitute a default, or deal with an unsubstitutable None at the edge, and design everything else in terms of the value.

                                                                With these operators apparently a nonzero subset of people think “I should just leave the value in the Option and touch its raw memory because “I know” I checked for presence once upstack”. Which works until someone refactors something and suddenly there’s a codepath that pulls the trigger on your footgun.

                                                                Good API design guides the user towards good usage. This clearly doesn’t.

                                                                It’s not a raw pointer, it’s a boolean paired with a value. There’s no necessary indirection.

                                                                It’s a raw pointer (T*) you’re getting back in the case of operator* and operator->, the operators this entire thread of posts is discussing. If you’re going to blindly call those you could equivalently have just slung around raw pointers wherever you acquired the option to begin with.

                                                                1. -1

                                                                  What if you already checked it once? Why should you be forced to check each time you access the contained value.

                                                                  Then extract the value the first time?

                                                                  Hmm I’m starting to doubt that you fully understand how optional works. A value is stored in the optional, not a pointer. Extracting the value results in copying a potentially large block of memory. There are many legitimate instances where it makes more sense to access the value from the optional without copying it.

                                                                  It’s not a raw pointer, it’s a boolean paired with a value. There’s no necessary indirection.

                                                                  It’s a raw pointer (T*) you’re getting back in the case of operator* and operator[], the operators this entire thread of posts is discussing. If you’re going to blindly call those you could equivalently have just slung around raw pointers wherever you used the option to begin with.

                                                                  operator*() returns a reference type. In any case, what is returned is irrelevant because an optional is a boolean paired with a value. It’s for situations when you need to pass around optional data in value form and can’t use pointers. Traditionally, optional return values were limited to pointer indirection (i.e. using NULL) but optional allows you to do the same without indirection.

                                                                  1. 1

                                                                    Hmm I’m starting to doubt that you fully understand how optional works.

                                                                    Spare me your condescension, oh self-appointed C++ guru. I’ve gotten paid more than enough for it over the years.

                                                                    I said “extract the value” as in, store a ref or move it or if it’s cheap copy it, but don’t just keep passing the optional around calling value or (god help you “because you cross your heart checked it upstack”) operator->. Luckily value safely gives you the same T& that operator* unsafely gives you. You can even move it safely, avoiding the need for expensive copies, if necessary.

                                                                    A value is stored in the optional, not a pointer. Extracting the value results in copying a potentially large block of memory. There are many legitimate instances where it makes more sense to access the value from the optional without copying it.

                                                                    Again, if you’re in a situation where: you have an optional value AND it’s too expensive to copy AND you want a reference to the memory in the optional AND you don’t want to pay for the single solitary check one time check when you call value to extract the value THEN either you’re terminally confused because you somehow think:

                                                                    if(opt.has_value) { 
                                                                       SomeVal& v = *opt
                                                                       // do something with v 
                                                                    } else { some other logic }
                                                                    

                                                                    is any amount of checks or derefs or copies faster than the safe alternative of

                                                                    SomeVal& v = opt.value_or(/* some other val */)
                                                                    // do things with v
                                                                    

                                                                    OR you absolutely can’t even deal with the overhead of the single check you do have so you’re intending to blindly do

                                                                    opt->foo
                                                                    opt->bar
                                                                    

                                                                    in which case, again just start with a pointer to the possibly undefined memory in opt and save the middleman.

                                                                    1. 0

                                                                      Hmm I’m starting to doubt that you fully understand how optional works

                                                                      Spare me your condescension, oh self-appointed C++ guru. I’ve gotten paid more than enough for it over the years.

                                                                      It’s not condescension, you were arguing along the assumption that optional as it currently exists has no benefit over using a raw pointer, completely ignoring the fact that it gives optional semantics to value types. That isn’t a dig at your general C++ knowledge, just your understanding of optional.

                                                                      You can even move it safely, avoiding the need for expensive copies, if necessary.

                                                                      std::move() is intended to speed up value types that contain pointers like std::vector. It doesn’t make moving a large struct fast.

                                                                      A value is stored in the optional, not a pointer. Extracting the value results in copying a potentially large block of memory. There are many legitimate instances where it makes more sense to access the value from the optional without copying it.

                                                                      Again, if you’re in a situation where: you have an optional value AND it’s too expensive to copy AND you want a reference to the memory in the optional AND you don’t want to pay for the single solitary check one time check when you call value to extract the value THEN either you’re terminally confused because you somehow think:

                                                                      There are serious caveats in defining value_or() in this construction: “SomeVal& v = opt.value_or(/* some other val */)”. How would you define it?

                                                                      in which case, again just start with a pointer to the possibly undefined memory in opt and save the middleman.

                                                                      I’ve already said that the point of optional is to give optional semantics for those cases when you must use a value type and not a pointer. Do you understand what that means? What if you can’t use the heap/a pointer?

                                                          3. -1

                                                            That’s not idiomatic C++.

                                                            1. 7

                                                              Could you clarify what you mean by idiomatic? What design would be both idiomatic but not permit dereferencing a null/uninitialized pointer?

                                                              1. 23

                                                                dereferencing a null/uninitialized pointer is idiomatic C++

                                                                1. 3

                                                                  and segfaults…

                                                                  It’s true that nullpointers may be valid addresses on some architectures but we should always model the semantics correctly in our programs.

                                                                  But what does not make sense is dereferencing an empty optional/smart-ptr. If a null-pointer is a valid and intended value than you should assign it to eg. your optional/smart-ptr.

                                                          4. 9

                                                            I mean, the semantics of Option in the abstract just aren’t safely compatible with an operation that blindly assumes Some(x) is present and directly grabs x’s memory, so the choices are either:

                                                            1. use exceptions to avoid unsafe accesses at runtime, which as you say, not every codebase will appreciate

                                                            Or

                                                            1. just don’t offer those operators on Option. They fundamentally compromise the entire point of the type. If you want to make blind assumptions about memory being initialized, use a raw pointer; Option should enforce its safety benefits.
                                                            1. -3

                                                              That’s not really how C++ works.

                                                              It offers those operators, you can use them if you want to, and if you don’t want to (which you clearly don’t) then don’t use them.

                                                              1. 13

                                                                It offers those operators

                                                                It offers implementors the choice to implement those operators on their types. There is absolutely no requirement that all types do so, let alone do so in a way that provides unsafe semantics. Their presence on std::optional makes little sense given the semantics of Option as an Abstract Data Type

                                                                1. 2

                                                                  Feels like Java 8’s Optional type all over again.

                                                                  1. 2

                                                                    As bad as Java 8’s Optional#get is, it at least always aborts control flow via an exception if an empty value is forced unwrapped.

                                                                    From what I can see, the undefined behaviour of C++ theoretically allows an implementation to not abort control flow and perhaps use zero values or something, which makes reasoning about control flow invariants in portable code harder.

                                                                    1. 1

                                                                      Why is Java’s Optional bad? Having used both Java and Rust, the only thing I really miss is pattern matching, which is a separate concern from the type itself.

                                                                      (I already know about the complaint that the optional itself can be null, but… baby steps, I guess.)

                                                                      1. 2

                                                                        “Bad” is honestly too strong a word for it; it got a lot right.

                                                                        That said, it gave a force-inwrapping operation the name get which is both too easy to discover and doesn’t signify the exceptional case well enough. A member of the JDK team admitted it was a mistake which is why it’s being deprecated in a future JDK for a more verbose name.

                                                                        The way it handles nulls is also annoying. Not because optionals can themselves be null like any other object, but because returning null in areas like mapping lambdas implicitly converts into empty optional rather than a present optional of a null. While getting rid of nulls like this seems like a good idea initially, it breaks the monadic laws which breaks composability in places.

                                                                        This article from Atlassian details the problem: https://blog.developer.atlassian.com/optional-broken/

                                                                        1. 1

                                                                          Eh. I think of the Java 8 stuff as occupying an intersection of two similar languages that don’t share all of their idiomatic patterns. I know that winds up resulting in yet more inconsistencies in spots, but I don’t know how much that bites people in practice.

                                                                          Then again, I acknowledge most of the stuff I’ve been working with is greenfield— there’s nothing to accidentally refactor the wrong way.

                                                                2. 1

                                                                  It offers those operators, you can use them if you want to

                                                                  meaning it offers you the option to introduce bugs to your codebase if you want to?

                                                              2. 3

                                                                What should it do? Throwing exceptions would make the API useless to many large consumers.

                                                                And undefined behavior makes it usable?

                                                        1. 10

                                                          My conclusion, based on reviewing evidence from numerous large software projects using C and C++, is that we need to be migrating our industry to memory safe by default languages (such as Rust and Swift).

                                                          I totally support this. C(++) is awesome for being so bare bones when working with low level stuff. But I feel software projects not needing such functionality could greatly benefit from safe languages.

                                                          1. 15

                                                            Could you elaborate on what you consider low-level stuff, where Rust, Ada, or other safe languages are not an option? You can compile Rust to STM32 microcontrollers with 20KB RAM and 64KB flash (with no_std), Rust has SIMD intrinsics for various platforms, etc.

                                                            To me, the major reason to go for C or C++ are ecosystems in which they are traditionally strong. gcc targets a lot of platform. Many embedded toolchains are only available for C or C++. The best traditional GUI libraries are in C or C++ (e.g. Qt). And (obviously) a gazillion lines of existing code are in C or C++, from open source unix kernels to deeply proprietary systems that will be used and maintained for decades to come.

                                                            Even though it may not be the (only) goal of the C++ standards committee, I see Modern C++ as a band-aid for maintaining C++-based systems that will be around for a long time, than a serious contender for modern, safe languages.

                                                            1. 1

                                                              Of course, ‘low level’ is very vague. I meant projects in which you want to use raw pointers and want to calculate with them, want to use CPU registers, want to have control over the produced asm, projects for very constrained platforms or obscure architectures, and so on. I do not necessarily mean other languages aren’t an option. I’m sure languages like Rust could replace a lot of C(++) code bases, even for these ‘low level’ things. In fact, I’d totally go for replacing such projects with a Rust variant if possible. But at the same time I can understand why some might choose to go with C(++).

                                                              1. 9

                                                                As far as I can tell as soon as your code is complex enough to make you want to move from C to C++ then you should probably reach for something safer. It’s hard to keep both the complexities of the invariants you need to manually ensure in your head while solving complex software problems.

                                                                1. 4

                                                                  ATS is an option here. It allows type safe use of low level pointers, including addiction, dereferencing, etc.

                                                              2. 2

                                                                C and C++ are completely different languages at completely different ends of a lot of spectrums. C is certainly bare bones, but C++ is not. What do you mean by ‘C(++)’?

                                                              1. 4

                                                                Sorry to go off on a tangent, but it’s unfortunate that they chose to implement their own Lisp-like language rather than write in Lisp in the first place. Writing it from scratch misses the point of Lisp as a DSL.

                                                                Judging by their example code, they could’ve written a few Common Lisp macros and had nearly identical state machine code. Then they could’ve focused entirely on the domain specific parts of the language and piggybacked on CL for the “boring” parts like arithmetic, looping, etc.

                                                                Granted Lisp isn’t very popular, but it’s more so than Radicle and there are many books and tutorials and pre-existing libraries (of varying quality, of course). But now their team will have to support a whole language ecosystem just to support the distributed state machine work they’re actually interested in.

                                                                1. 3

                                                                  We needed, for this entire architecture to work, a language that is deterministic. If there’s some compiler extension that restricts CL to only the deterministic parts, that could have worked. But (and I have to admit I’m relatively ignorant about CL here) I’d be surprised if that were easy, and didn’t imply most tutorials and libraries wouldn’t work anyhow.

                                                                  1. 2

                                                                    I’m not sure I understand the use of “deterministic” here. Which parts of CL are non-deterministic?

                                                                    In any case, I used CL as the example because it’s what I use, but a simpler Lisp with macros, like Scheme, should also work.

                                                                    1. 4

                                                                      By “deterministic” I mean that the language should be such that, for any program written in it P, and for any inputs to that program I, the result of running P with I, P(I), should always be the same between runs, for everyone. So no IO, no platform-specific behavior, no concurrency, no randomness, no weak refs that allow observing garbage collection results, etc.

                                                                      1. 2

                                                                        The state machines defined using Radicle need to be deterministic, but that doesn’t require the language defining the state machines to be deterministic.

                                                                        1. 9

                                                                          That’s true, but then that would require a separate proof for each machine (or the risk of a mistake). The idea behind Radicle is a special purpose programming language in which all programs are automatically deterministic state machines.

                                                                        2. 1

                                                                          Why not just use a pure language?

                                                                    2. 2

                                                                      chose to implement their own Lisp-like language rather than write in Lisp in the first place.

                                                                      I’m not sure it’s from scratch…. “Lisp dialect in the flavor of Black.” combined with the fact Black’s flavour is…

                                                                      Black is an extension of Scheme with a reflective construct exec-at-metalevel. It executes its argument at the metalevel where the interpreter that executes user programs is running. There, one can observe, access, and even modify the metalevel interpreter in any way. Because the metalevel interpreter determines the operational semantics of the language, Black effectively allows us to observe, access, and modify the language semantics from within the same language framework.

                                                                      ie. I’m curious to know to what extent it’s “implement their own Lisp-like language” vs a “scheme minus mutability” with a Black program that mutates Black.

                                                                      After all Scheme isn’t exactly a massive language.

                                                                      1. 1

                                                                        After all Scheme isn’t exactly a massive language.

                                                                        It’s … a fair bit bigger than that. That doesn’t even implement all of r4rs. The most recent standard, r6rs (from 2007), expanded the language so significantly than many (real, non-toy) schemes still haven’t implemented everything.

                                                                        I agree with your overall point, just that your example is misleading.

                                                                        1. 1

                                                                          The most recent standard is r7rs and as I understand it, it makes the language smaller than r6rs.

                                                                          1. 1

                                                                            I forgot about r7rs. IIRC, that added so many things to the language that they split it into two specs: the big one and the small one (the latter which is closer to r5rs (again, iirc)).

                                                                        2. 1

                                                                          What I was getting at is the language isn’t written in Lisp or Scheme, but is a Lisp-like language written in Haskell. The power of Lisp as a DSL is that macros allow the language to be seamlessly extended using the language itself. Instead of writing an entire compiler, they could have written a few macros.

                                                                          The nondeterminism argument that jkarni and jameshh brought up kind of makes sense, but seems like it would be easy to circumvent by generating Radicle code at runtime.

                                                                          1. 1

                                                                            Well, the meta-level stuff is interesting and does more than a macro could do…. and not available in the Lispy things I have used…

                                                                            I wonder if and what they use it for…

                                                                      1. 1

                                                                        This utopia seems to be a utopia for people that don’t much like the FSF or the GPL.

                                                                        Where’s the license for people that think that the GPL actually captures software freedom appropriately? I could see an argument that despite the ideals of a license utopia, the FSF will release a license anyway (and probably GPLv4 at some point) so there’s no point just creating a new one to replicate it, but this is supposedly to replace all existing free software licenses right? So where’s the one that corresponds to the vast majority of free software licenses currently in use: the GPL?

                                                                        1. 2

                                                                          It would be odd to me for UNIX concepts to co-opt a ’‘shell’’ tag. Are Window’s Powershell or DOS’s various shells no longer ’‘true shells’’? There are also the shells from Multics, VMS, Genera, Oberon, and many others.

                                                                          If you want to mean only UNIX shells, then what’s wrong with the UNIX tag that already exists?

                                                                          1. 1

                                                                            My struggle with unix is that I’m not entirely sure it’s the right place for projects like prezto, oh-my-zsh, and zsh-utils… as well as more in depth shell scripting. I see your point… maybe “shell” isn’t the right tag, but it seems like a decent option and I don’t have any other alternatives.

                                                                            1. 1

                                                                              ‘windows’ + ‘cli’ vs ‘unix’ + ‘cli’ is a sufficient distinction isn’t it?

                                                                              1. 1

                                                                                Yeah, I suppose that does make sense

                                                                          1. 1

                                                                            Why would someone submit a link that already appeared four year ago? Has there been some interesting new development about it? If so, maybe link to a blog article or whatever discussing that instead. (If there isn’t one, write one!)

                                                                            One could argue that lobsters is a kind of news aggregator and anything that appears on the front page should arguably be new, or at least something we haven’t seen before. I’m not sure it’s a good idea to resubmit a link just because it hasn’t been seen for a while. Otherwise I can imagine some users taking this to an extreme and posting a link to their favorite vim plugin every month.

                                                                            1. 2

                                                                              Lobsters has changed a lot in 4 years. There’s a much bigger audience than there was then.

                                                                              I don’t think of Lobsters as a news aggregator. It’s not HN or reddit and it benefits from not being HN or reddit.

                                                                              Otherwise I can imagine some users taking this to an extreme and posting a link to their favorite vim plugin every month.

                                                                              I think there’s definitely a line somewhere between ‘one person resubmitting something someone else posted 4 years ago’ and ‘one person resubmitting something every month’.

                                                                              1. 2

                                                                                I think it is good idea to be able to resubmit - as it brings awareness back to the subject. I have come across many good articles on their second submission, as I missed them on first submission.

                                                                              1. 10

                                                                                The comment section on the linked post is is full of people getting upset at the very idea of someone not liking Rust. Never seen that before…

                                                                                1. 10

                                                                                  Never seen that before…

                                                                                  It seems common enough to me. At least I have seen it in action plenty of times, especially over on HackerNews. There is even a joke/moniker for it: “Rust Evangelism Strike Force”. People tend to get very worked up and defensive about things they like I suppose.

                                                                                  Do note that it definitely seems, based on what I have read, that such behavior is generally frowned on by the Rust team itself. It also /maybe/ doesn’t seem quite as prevalent as it used to? Not sure.

                                                                                  1. 4

                                                                                    Yes, there is an ongoing significant effort by many of the people in the Rust community to actively work against aggression. There are a lot of messages happening behind the scenes on the platforms that support it where people will be asked to use language that will be more welcoming.

                                                                                    1. 5

                                                                                      Yeah I was being sarcastic :)

                                                                                      Do note that it definitely seems, based on what I have read, that such behavior is generally frowned on by the Rust team itself.

                                                                                      Given that people like Steve Klabnik do it on reddit all the time, I doubt that’s the case

                                                                                      1. 10

                                                                                        Steve can often be seen disagreeing with things he views as mischaracterizations, usually in a pretty respectful way. I can’t think of an example of him being upset that someone didn’t like rust though.

                                                                                        I think people sometimes get the impression that he is on the RESF because he can be seen engaging everywhere, but he’s really advocated strongly for NOT doing what you describe. If you’re everywhere, you tend to get associated with the people who might seem to be “on your side” even if they are going about that in a way that you really disagree with. I don’t think Steve would consider people on the RESF to be on his side at all, though.

                                                                                        1. 2

                                                                                          Well, also cuz it was his job to be everywhere promoting it. All the community team members have publicly denounced the kind of behavior in that comment thread, though. They know it’s not good for their goals. Certainly not coming from them. Just Internet as usual.

                                                                                    2. 6

                                                                                      I’ve seen it often enough that I don’t bother talking about Rust any more.

                                                                                      I’m a C++ developer, but I keep an eye on Rust and Go just to stay up on what’s going on in “systems languages”. I’ve mentioned several times that I don’t see a big advantage to using Rust, since I already know C++ well enough to avoid most of the errors Rust solves. Valgrind, Coverity, and newer C++ features like shared_ptr can eliminate a lot of the errors that Rust tries to solve.

                                                                                      But according to some Rust zealots, there’s no way that’s true, and the mere fact that I’ve suggested it means I’m ignorant to the problem and I’m causing buffer overflows left and right.

                                                                                      EDIT: Too early, took me a minute to notice it’s sarcasm

                                                                                      1. 3

                                                                                        newer C++ features like shared_ptr can eliminate a lot of the errors that Rust tries to solve.

                                                                                        unique_ptr is slightly harder to misuse, IMO. shared_ptr preserves the ownership quandary that Rust helps mitigate.

                                                                                        Undefined behavior is everyone’s nemesis, IMO. UBSan helps but

                                                                                        I already know C++ well enough to avoid most of the errors Rust solves

                                                                                        And so you probably know it well enough to recognize the bugs you’ve introduced when you’ve spent some time debugging an issue.

                                                                                        Valgrind, Coverity, and …

                                                                                        IMO if you value static checkers like Coverity’s, then it stands to reason that you might like a Sufficiently Smart Static Checker. But if C/C++ had to be constrained to a subset of the current language in order to give that Sufficiently Smart Static Checker the additional context it needed to find bugs, would you still find it interesting? If the answer’s “yes”, then it seems to me like Rust isn’t far from what you’d get from a constrained C++. If the answer’s “no” then maybe C++ is ideal for your use.

                                                                                        cargo and the crates infrastructure is Rust’s big win, in my opinion. Safety features are just the entrance criteria for a new language.

                                                                                        1. 1

                                                                                          I’m not a Rust zealot, but I settled on the default approach of “if you are using C or C++ for new things in 2019, there is something going horribly wrong; but I’m open to hear the reasoning to convince me otherwise”.

                                                                                          Nothing is worse than C/C++ developers thinking they understand their language, despite a million man-decades of evidence pointing to the exact opposite.

                                                                                          1. 6

                                                                                            There is a difference between knowing it well enough to write a compiler compliance suite, and knowing it well enough to quickly deliver business value.

                                                                                            Please do not keep parroting the same “C/C++ is evil” meme, and certainly don’t lump them together.

                                                                                            1. 3

                                                                                              The only difference is whether the result of not knowing it well enough will kill people or just slightly reduce some business value (isn’t it crazy how C and C++ have trained the general populace to not even expect programs to be reliable?).

                                                                                              Please do not keep parroting the same “C/C++ is evil” meme, and certainly don’t lump them together.

                                                                                              It took people a few decades to figure out that smoking kills, so regardless of whether you consider it “evil”, I hope that in the future C++ compilers ship with mandatory shock pictures that show the consequences of using C++.

                                                                                              1. 3

                                                                                                isn’t it crazy how C and C++ have trained the general populace to not even expect programs to be reliable?

                                                                                                Please provide evidence for such big claims. As a personal anecdote, I have to deal with much more unreliability caused by Java software than by C/C++.

                                                                                            2. 1

                                                                                              FWIW, this is exactly the type of response I was talking about. You’re right, obviously I have no idea what I’m doing.

                                                                                              I’m not interested in this tedious argument, so I won’t be replying again.

                                                                                          2. 2

                                                                                            Yeah, there were some assholes in there. They should knock it off given it’s certainly not doing any favors for Rust adoption or even making new friends who work on cool projects like Dust3D.

                                                                                          1. 1

                                                                                            On having bloated dependencies, badly formatted code and no git tags? Absolutely agreed. Those are all bad signs. I’m sceptical about the rest.

                                                                                            There are a lot of bad READMEs out there no doubt. But the suggestion that you should fill your README with badges instead of it being a proper README with nicely formatted text I can read in a text editor is juvenile.

                                                                                            Licenses? What if I don’t actually care about some stupid company using my code? I’d rather they didn’t, actually, so I use Artistic License 2.0 or AGPLv3. The presumption that people writing and publishing free software are keen to have some company make money on their work is strange to me.

                                                                                            It’s up to you to write yourself a Dockerfile for your projects, not me. I don’t use Docker.

                                                                                            GitHub pull requests are a horrible way of managing software changes that ruin commit history and create a huge amount of noise in changes. They make it virtually impossible for anyone other than the original pull requester to change the code in the pull request without recreating the whole pull request. They’re just.. bad.

                                                                                            Tests, automated builds, etc. are not necessary at all.

                                                                                            1. 2

                                                                                              Can this be tagged as web as well please? One of the points that was brought up when this tag was suggested was that accessibility-related content is web-accessibility-related. I want to be able to filter out web-related content without filtering out all accessibility-related content.

                                                                                              1. 3

                                                                                                You can use the “suggest” button to add tags. I’ve suggested web now.

                                                                                              1. 17

                                                                                                Another disadvantage of services is that you can’t do a database transaction that includes operations from more than one service.

                                                                                                Unrelated, I worked at a place a few years ago that built microservices because they wanted the various services to work concurrently, and they were using Ruby. Unfortunately, trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough. It also forced me to switch from a spinning disk to a solid state one simply because of the number of files being loaded at once.

                                                                                                That experience was part of what motivated me to learn Elixir. Years later, I recently worked on an Elixir umbrella app. It was like microservices, but running the whole thing was easy. In production, they deployed one app to one server, one to another, and let both of them depend on a third app, which was deployed to both. All the apps that needed a database shared the same one.

                                                                                                1. 24

                                                                                                  Unfortunately, trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough.

                                                                                                  Don’t do that. You need to deal with network issues anyways, so bring them all up and let your error handling take care of it.

                                                                                                  1. 8

                                                                                                    trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough.

                                                                                                    I don’t know you usecase, but that seems to be a complex thing to implement that probably shouldn’t be needed.

                                                                                                    1. 2

                                                                                                      systemd has service dependencies and sd_notify built-in. Few people use it but it’s totally possible to start a web of services. Of course this doesn’t help with off-machine resources.

                                                                                                      http://0pointer.de/public/systemd-man/systemd.service.html

                                                                                                    2. 6

                                                                                                      Another disadvantage of services is that you can’t do a database transaction that includes operations from more than one service.

                                                                                                      You absolutely can; I do all the time. It may require fundamentally rethinking what we mean by “database” though.

                                                                                                      Most people think a database is somewhere between “a black box that stores data” and “a black box of hard algorithms for data query” or something like that. To them, they conveniently ignore that the “database” is a service outside of their application, and “can’t transact” across that service boundary either. That’s part of why database migrations and schema changes are so hard: Version 2 and Version 3 of your application are potentially separate services – even in the monolith – and because you “can’t transact” between versions of your application (what does that even mean!?) you’re forced to put logic into your application to deal with both the old schema and the new schema, and you may even often have to do on-the-fly upgrades.

                                                                                                      Or you just have downtime.

                                                                                                      Or you have a whole separate system, and your “transaction switch” is on some kind of network load balancer. Blue/green or whatever you want to call it.

                                                                                                      However there’s a very different way: If your application is the database (and this is easier than you probably think), your crud operations simply need to log their intentions, and then have something read the log which materialises the results into views you can use.

                                                                                                      One way to do this is to go heavy on the stored procedures. I like this approach, but SQL is a really terrible application language, and many programmers are very bad at SQL. Many databases don’t have an audit table for the stored procedures – there isn’t very good version control for them, so that’s another reason people don’t like it. Maybe the tooling could be improved though.

                                                                                                      Most people usually go the other way.

                                                                                                      In Erlang/Elixir, I may (for persistence) use a disk_log to write out arbitrary terms, and have a subscriber pick them up – that is also a gen_server that you can query. At startup, I can read the logs. If the logs are big, my gen_server knows enough to checkpoint – just write out State to another file, and include the offset in the disk log.

                                                                                                      In Go and Smalltalk you can do something similar.

                                                                                                      In C, or lots of other languages that don’t have processes, you can still get this functionality with a little thought, because the operating system has processes and fifos/socketpairs for you to use! It feels very similar to writing microservices, which sucks for different reasons (notably the lack of good IPC, e.g. php has serialize), but it’s not the same as microservices: just mutually cooperating processes. Qmail is a great example of this architecture, that is probably just a bit more complex than it would need to be today since the whole world is Linux and iOS now.

                                                                                                      In q I don’t even need to do that. I can just use the -l and -r options which give me logging/subscription built-in to the runtime. It’s also much more enjoyable because the language doesn’t suck as bad as SQL, and we have great IPC.

                                                                                                      Putting your data responsibilities in your application isn’t popular though. People actually think redis or Postgresql are fast, and many programmers doubt themselves able to make something as fast (let alone faster). This kind of approach however, tends to be done well around 1000x faster than using “a database” (and maybe done poorly or naïvely only 10x faster), gets you 100% uptime even in the face of schema changes, all of the benefits of a distributed/multiservice application with none of the downsides.

                                                                                                      This is, as I see it, a serious barrier: Programmers lack the confidence to build things outside of their specialisation (whether they call it “back end” or “front end”) and even terms like “full stack” seem to be (in their normal usage of the term) limited to “code” – very few “full stack” developers seriously consider rolling a new database for every application. And I think they should.

                                                                                                      1. 1

                                                                                                        What is q ?

                                                                                                        1. 1
                                                                                                      2. 3

                                                                                                        Another disadvantage of services is that you can’t do a database transaction that includes operations from more than one service.

                                                                                                        You can using distributed transactions, but that’s a whole other nightmare to contend with.

                                                                                                        1. 2

                                                                                                          Unfortunately, trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough.

                                                                                                          Topological sort?

                                                                                                        1. 16

                                                                                                          This is a bad article in my opinion, it doesn’t make any arguments, just assumes that you need a very good reason to do “operator overloading”, and since he can only think of one (a DSL) then that’s the end of the argument.

                                                                                                          I reject the premise that operator overloading is inherently something to be avoided at all costs, in fact I think it’s very pythonic. sqlalchemy overloads operators on column to great effect, you could say it’s a DSL but I don’t know a clear dividing line between any library that becomes very well fitted to it’s domain and a DSL, in a dynamic language.

                                                                                                          Further reject the premise that call is best thought of as operator overloading (or the sort people tell you to avoid). Some of the arguments for why to avoid overloading don’t apply - if you overload + for a class, then every time someone reads + in your codebase they need to be aware that the operands might include your class (where before it was only a small set of types allowed). There’s also two types involved so the dispatch can be complicated.

                                                                                                          If you overload call, now they need to be aware that when something is called eg x(), it could be a function or a class. But that’s not really important since functions can take and return anything and store state, and so can classes. From a consuming perspective there really isn’t an important difference. There’s only one type involved so dispatch is much simpler.

                                                                                                          His readability argument (he just states “more readable”), I can only think of 2 reasons, 1: you don’t know call, in which case go read a textbook. 2: call means you get 1 less name vs a named method. In lots of cases though, the name of the method would reasonably be identical to that of the class, these are the most common cases where I think call is appropriate.

                                                                                                          1. 2

                                                                                                            You’re right in that it’s fine to use call when it is appropriate. However, I agree with the article that it’s not something you should be doing “just because you can”. If you look at code that instantiates an object and then uses the object as a function, it is more confusing than simply calling a method on the object. It is overly “cute” and non-obvious. In most cases, simple code that does not obscure what is going on is better than code that is slightly harder to follow.

                                                                                                            Yes, as an experienced Python developer, you should be aware that an object may be callable via magic methods, but it’s way easier (especially for developers less experienced with the language) to follow code that doesn’t rely on such “tricks”. I’m a big proponent of using language constructs well, but I think their use is similar to “big” words in a natural language; you can eloquently express yourself by using them, but if you over-use them, it makes you seem pompous and harder to understand, even for people that have a large vocabulary. No everyone is at the same level you are. Sure, you can look it up in a textbook, just like you can look up new words in a dictionary. But not requiring the less fluent reader to do so unnecessarily is a mark of skill for an author.

                                                                                                            Of course there are many situations where using callable objects is suitable: like you said the SQLAlchemy DSL, or situations where code requires a callable, but you need to do more bookkeeping than is practical with a closure (which would happen when you’re using an API in a slightly different way than intended). Right tool for the job and all that…

                                                                                                            1. 1

                                                                                                              Yes, as an experienced Python developer, you should be aware that an object may be callable via magic methods, but it’s way easier (especially for developers less experienced with the language) to follow code that doesn’t rely on such “tricks”.

                                                                                                              In my opinion code shouldn’t be written poorly so that it’s easier for newbies to follow. If you can make it easier for newbies to follow without sacrificing anything then that’s good, but in this exact case in the article, a method ‘get_name’ is used instead and that name is more confusing than just using __call__!

                                                                                                              1. 1

                                                                                                                In my opinion code shouldn’t be written poorly so that it’s easier for newbies to follow.

                                                                                                                I didn’t mean to imply that you actively dumb down your code. I just meant that using more “complex” features should be carefully considered and only used when necessary or definitely clearer.

                                                                                                                If you can make it easier for newbies to follow without sacrificing anything then that’s good, but in this exact case in the article, a method ‘get_name’ is used instead and that name is more confusing than just using call!

                                                                                                                Maybe a better name of the method would be store_matching_filename or something like that, because that’s what it is doing. You could also argue that this is a DSL that matches files so it’s fine to use __call__, and if it’s part of a bigger library or system with more such classes that might definitely be the way to go. But for a one-off file matcher I’m not sure I would do this. Of course, it’s quite a contrived example so it’s neither here nor there.

                                                                                                          1. 0

                                                                                                            Is accessibility a technical topic in its own right? The thing is, all the examples you gave are about web accessibility, and the interesting technical content in them is web-specific. It seems likely that the interesting technical parts of any accessibility article would be able to be tagged already, probably?

                                                                                                            1. 5

                                                                                                              One argument is that it’s impossible to separate politics and technology, since technology impacts people. Having an accessibility tag would help raise awareness about issues that we might find ourselves positioned to help fix.

                                                                                                              That might be a weak argument here, but it seemed worth mentioning.

                                                                                                              1. 0

                                                                                                                Accessibility isn’t political.

                                                                                                                My question is not ‘what makes accessibility interesting’ but really whether there are any accessibility articles being written that aren’t about web accessibility and have interesting technical content.

                                                                                                                1. 6

                                                                                                                  I would argue that since we have a security tag that is mostly for web security it makes sense to have an accessibility tag. Accessibility is a concern in all software that a user interacts with, the fact that the articles posted are about the web doesn’t mean it isn’t a concern outside of the web.

                                                                                                                  EDIT:

                                                                                                                  Here are some articles that would be valid submissions to lobsters that are about accessibility and not about the web:

                                                                                                                  EDIT 2:

                                                                                                                  Here are some lobsters submissions I found that were about accessibility and not about the web (some are about design and others are about application development in general):

                                                                                                            1. 1

                                                                                                              I had some pretty heated arguments at my old job with a coworker that just put in zero effort to fit in with others and adhere to code standards. He would mix tabs and spaces in awful ways, his lines of code were too long, his code used far too much whitespace (a newline between every line of code, three between functions, etc.), badly named variables, overly complex code to achieve simple tasks.. just every problem you could imagine. And I don’t regret saying so over and over again. The solution to a lot of the problems was simply to add a linter and he just ignored the linter warnings.

                                                                                                              It’s not toxic to review code and point out the issues within it. It’s unnecessary to tag every instance of every type of mistake in code, but it is important to review code and fix it. The idea that you shouldn’t critically review code simply because it’s ‘toxic’ is insane.

                                                                                                              One thing I think is a big issue is that it’d be SO much easier if I could just go and make the changes myself. You have your branch, you push it, I want to fix a formatting issue, it’d be much easier for me to just go and make the changes myself than to point them out and have you fix them…

                                                                                                              1. 7

                                                                                                                I don’t understand why people willingly subject themselves to golang… I have to do it at work, but I would never do it at home.

                                                                                                                1. 13

                                                                                                                  Do we have to have this conversation on every thread tagged go?

                                                                                                                  1. 6

                                                                                                                    Part of it is the ability to compile to a single binary without much ceremony. I’m currently faced with some deployment code that is a combination of bash, python, and C++. There are many ways to make this situation better but one simple way is to consolidate the pieces into something more self-contained and independent. Go fits the bill but so do other languages like D, Crystal, Rust, Dart, etc. I haven’t yet settled on a course but Go is probably going to win because it has much larger mindshare than the other languages.

                                                                                                                    1. 5

                                                                                                                      Part of it is the ability to compile to a single binary without much ceremony.

                                                                                                                      110% this. Whenever I’m writing a small thing to distribute, the pain of writing it in go is nothing compared to the pain of setting up cross-compilation (even compared to e.g. rust, where it’s pretty straightforward, it’s much more work than go).

                                                                                                                      1. 2

                                                                                                                        even compared to e.g. rust, where it’s pretty straightforward, it’s much more work than go

                                                                                                                        What is more work than Go? Compiling a single binary? Cross-compilation? Or writing Rust itself? Just curious.

                                                                                                                        1. 2

                                                                                                                          Cross compilation. Go is the gold standard there.

                                                                                                                          1. 3

                                                                                                                            Ok, thanks! I don’t have a lot of experience with cross-compiling Rust, but compiling for STM32 microcontrollers from x86_64 darwin was like a walk in the park.

                                                                                                                    2. 2

                                                                                                                      For me:

                                                                                                                      • gofmt
                                                                                                                      • nice stdlib
                                                                                                                      • static binaries
                                                                                                                      1. 1

                                                                                                                        I’ve managed to avoid it at work so far, but I’m expecting that to change soon. But I dove in at home a few years ago as a replacement for ruby for building small utilities to help me automate stuff on my own machines. I really didn’t like writing it, but it struck me that it would be a great target for transpilation; things that you compile to JS for the web, you’d compile to golang instead of node for the backend.

                                                                                                                      1. 1

                                                                                                                        One would have hoped to see, in a complaint about names, that the article would at least spell “PostsgreSQL” correctly.

                                                                                                                        1. 1

                                                                                                                          I think that might be the joke

                                                                                                                          1. 1

                                                                                                                            Perhaps? More ambiguous, at least, than earnest use of the word oriental.

                                                                                                                            1. 0

                                                                                                                              What’s wrong with oriental?

                                                                                                                              1. 2

                                                                                                                                “Oriental” is a term coined and used by those from Europe and America (whether in colonized lands or otherwise) to group together many disparate ethnic groups and cultures based on stereotypical presumption. This is evident by the expanding and contracting specific definitions the word takes on geographically speaking; the only loose “glue” holding these things together is a general, stereotyped, idea of “Eastern” culture.

                                                                                                                                1. 2

                                                                                                                                  Agree about “Oriental”, but can’t help but notice the irony in referring to “those from Europe and America” while complaining about “general, stereotyped, idea of “Eastern” culture”.

                                                                                                                                  If you want to talk about large numbers of people, you can only do so by using an abstraction which obscures details not relevant to the topic.

                                                                                                                                  That’s true whether the abstraction is “Westerners”, “Orientals”, “Males”, or “Programmers”.

                                                                                                                                  1. 1

                                                                                                                                    “Oriental” is an English term. It’s going to be used by English speakers, who are predominantly from Europe and America. Please comment when you find it in common parlance in a country without an English-speaking majority.

                                                                                                                                    1. 0

                                                                                                                                      We just did this thread, and it got pruned. Probably not a great idea to do it again.

                                                                                                                                  2. 1

                                                                                                                                    It’s usually reserved for rugs these days. There’s nothing inherently ‘wrong’ with almost any word, but certain words acquire negative associations, and ‘oriental’ is one of these; its use to describe non-rug entities has racist connotations (though, of course, not always intended).

                                                                                                                                    1. 3

                                                                                                                                      I used it on purpose. My gf is reading Orientalism and I couldn’t miss the chance

                                                                                                                                      1. -3

                                                                                                                                        Well it doesn’t have a negative association here… Not everyone is an American that gets offended by everything.

                                                                                                                              1. 4

                                                                                                                                Rust as a name was widely derided when it first came out. People pointed out that the name ‘Rust’ is a name that is invariably associated with the oxidation of iron, something that has negative connotations everywhere with decay, lack of maintenance. ‘But it’s named after a fungus’ really doesn’t help with that image either.

                                                                                                                                Swift was also a funny one. When it came out, at least, it was anything but! It was slower than CPython in many simple numerical tasks, like simple for loops, and its type inference engine had some nasty bugs that lead to massive exponential slowdowns in performance.

                                                                                                                                It annoys me when people say things like ‘programmers are notoriously awful at naming things’. It’s true that they are notorious for this, but it’s not actually true that programmers are awful at naming things at all. It’s nonsense dreamed up by marketing people that think that taking words that end in ‘er’ and making them end in ‘r’ instead is clever naming.

                                                                                                                                1. 1

                                                                                                                                  Fair point. What I had in mind was things like variable and class names, API endpoint names…that I’ve personally encountered.