Threads for moderan

  1. 14

    Terrible article. The author simply mashes together concepts while apparently having only a superficial understanding of any of them. The comparison of uxn to urbit is particularly hilarious, considering that they have totally different goals. Well, yes, both are virtual machines and that is where it ends.

    Simplicity and elegance have appeals beyond performance, like ease of understanding and implementation, like straightforward development tool design. Judging the performance of a VM that (from what I see) has never been intended to be high-speed based on some arbitrary micro benchmark also doesn’t really demonstrate a particularly thorough methodology (the pervasive use of “we” does make the article sound somewhat scientific, I do grant that…)

    I suggest the author invests some serious effort into studying C. Moore’s CPU designs, the true meaning of “simplicity”, the fact that it can be very liberating to understand a software system inside out and that not everybody has the same goals when it comes to envisioning the ideal piece of software. The article just critizes, which is easy, but doesn’t present anything beyond that.

    1. 13

      Terrible article. The author simply mashes together concepts while apparently having only a superficial understanding of any of them.

      I suggest the author invests some serious effort into studying C. Moore’s CPU designs, the true meaning of “simplicity”, the fact that it can be very liberating to understand a software system inside out

      I don’t exactly agree with the author’s criticism of uxn (probably because I see it purely as a fun project, and not a serious endeavor), but let’s not descend into personal attacks please.

      1. 15

        Thanks.

        Now, with that out of way - this is not at all personal, the author is simply misrepresenting or confused, because there are numerous claims that have no basis;

        It is claimed this assembler is like Forth, but it is not interactive, nor it have the ability to define new immediate words; calling and returning are explicit instructions. The uxntal language is merely an assembler for a stack machine.

        Must Forth be interactive? What sense make immediate words in an assembler? Returning is an explicit instruction in Forth (EXIT, ;). That sentence suggests some wild claim has been made, but I can’t see where.

        Using software design techniques to reduce power usage, and to allow continued use of old computers is a good idea, but the uxn machine has quite the opposite effect, due to inefficient implementations and a poorly designed virtual machine, which does not lend itself to writing an efficient implementation easily.

        Again, I suggest studying Moore’s works, Koopman’s book and checking out the “Mill” to see that stacks can be very fast. The encoding scheme is possibly the simplest I’ve ever seen, the instruction set is fully orthogonal. A hardware implementation of the design would be orders of magnitude simpler than any other VM/CPU. Dynamic translation (which seems to be the author’s technique of choice) would be particularly straightforward. I see no poor design here.

        The uxn platform has been ported to other non-Unix-like systems, but it is still not self-hosting, which has been routinely ignored as a part of bootstrapping.

        This makes no sense. Why self-host a VM? “Routinely ignored”? What is he trying to say?

        After that the author discusses the performance of the uxn VM implementation, somehow assuming that is the only metric important enough to warrant an assessment of the quality of uxn (the “disaster”).

        Vectorisation is also out of the question, because there are no compilers for uxn code, let alone vectorising compilers.

        What does the author expect here?

        We can only conclude that the provided instruction sizes are arbitrary, and not optimised for performance or portability, yet they are not suitable for many applications either.

        (I assume data sizes are meant here, not instruction sizes, as the latter are totally uniform) Uxn is a 8/16 bit CPU model and supports the same data sizes as any historical CPU with similar word size. Again, I get the impression the author is just trying very hard to find things to complain about.

        Next the author goes to great lengths to evaluate uxn assembly as a high level programming tool, naturally finding numerous flaws in the untyped nature of assembly (surprise!).

        a performant implementation of uxn requires much of the complexity of modern optimising compilers.

        The same could be said about the JVM, I guess.

        To get to the end, I can only say this article is an overly strenous attempt to find shortcomings, of whatever nature, mixing design issues, implementation details, the authors idea of VM implementation, security topics, at one moment taking uxn as a VM design, then as a language, then as a compiler target, then as a particular VM implementation, then as a general computing platform.

        I like writing compilers, I have written compilers that target uxn, it is as good a target as any other (small) CPU (in fact, it is much easier than, say, the 6502). Claiming that “the design of uxn makes it unsuitable for personal computing, be it on new or old hardware” is simply false, as I can say from personal experience. This article is pure rambling, especially the end, where sentences like this that somehow let me doubt whether the author is capable of the required mental detachment to discuss technical issues:

        Minimalist computing is theoretically about “more with less”, but rather than being provided with “more”, we are instead being guilt-tripped and told that any “more” is sinful: that it is going to cause the collapse of civilisation, that it is going to ruin the environment, that it increases the labour required by programmers, and so on. Yet it is precisely those minimalist devices which are committing these sins right now; the hypocritical Church of Minimalism calls us the sinners, while it harbours its most sinful priests, and gives them a promotion every so often.

        No, brother, they are not out there to get you. They just want simple systems, that’s all. Relax.

        As O’Keefe said about Prolog: “Elegance is not optional”. This also applies to CPU and VM design. You can write an uxn assembler in 20 lines of Forth. There you have a direct proof that simplicity and elegance have engineering implications in terms of maintenance, understandability and (a certain measure of) performance.

        1. 16

          I agree with you in the sense that doing something for fun is obviously allowed, but I feel like the criticism in the article is not that you shouldn’t build anything simple and minimalist for fun, but that the things we build are usually not as revolutionary as some may claim just because they’re simple. Now, if the author of uxn made no such claims then that’s fine; however, that doesn’t mean something cannot be criticized for its perceived flaws (whether you agree with the style and tone of the criticism or not).

          I also agree that the Church of Minimalism stuff is a bit over-the-top.

          1. 6

            FWIW I had exactly the same reaction to this article as you, and I haven’t even heard of any of these projects. The article seems like it is in bad faith.

            Minimalist computing is theoretically about “more with less”, but rather than being provided with “more”, we are instead being guilt-tripped and told that any “more” is sinful: that it is going to cause the collapse of civilisation, that it is going to ruin the environment, that it increases the labour required by programmers, and so on. Yet it is precisely those minimalist devices which are committing these sins right now; the hypocritical Church of Minimalism calls us the sinners, while it harbours its most sinful priests, and gives them a promotion every so often.

            This part in particular is so hyperbolic as to be absurd. Completely unnecessary. Still, I guess if your goal is to garner attention, hyperbole sells.

            1. 12

              This part in particular is so hyperbolic as to be absurd. Completely unnecessary. Still, I guess if your goal is to garner attention, hyperbole sells.

              I wouldn’t say so. I’ve had folks tell me on tech news aggregators that the only way to make computing ethical is for computing to be reimplemented on uxn stacks so that we can all understand our code, or else the code we use can be used for exploitation. Now this may not be the actual uxn project’s stance on the matter at all, but much like Rust seems to have a bit of a reputation of really pushy fans, I think it’s fair to say that uxn has attracted a fanbase that often pushes this narrative of “sinful computing”.

              1. 2

                Oh interesting, do you have any links? I’m intrigued by this insanity.

                Edit: though presumably this is a vocal minority, making this still quite a hyperbolic statement.

                1. 3

                  I did a light search and found nothing off-hand. I’ll DM you if I manage to find this since I don’t like naming and shaming in public.

                  Edit: And yeah I’m not saying this has been my experience with a majority at all. The folks I’ve heard talk about uxn have been mixed with most having fun with the architecture the same way folks seem to like writing PICO-8. It just has some… pushy folks involved also.

                  1. 7

                    I believe the only way to make computing ethical is to reinvent computing to do more with less. I also believe uxn is trying to reinvent computing (for a very specific use case) to do more with less. But those two statements still don’t add up to any claim that it’s the only way out, or even that it’s been shown to work in broader use cases.

                    Disclaimer: I’ve also tried to reinvent computing to do more with less. So I have a knife in this fight.

              2. 4

                Actually, we regularly get posts here on lobste.rs espousing exactly that sort of ideology. I think there’s one or two trending right now. perhaps you’ve hit on the right set of tag filters so you never see them?

            2. 2

              “C. Moore…” as in Chuck Moore…

              1. 1

                The paste was cut off. Fixed.

            3. 13

              The comparison of uxn to urbit is particularly hilarious, considering that they have totally different goals.

              they both market themselves as “clean-slate computing stacks”, they both begin with a basic admission that no new OS will ever exist (so you have to host your OS on something else), they both are supported by a cult of personality, they both are obsessed with ‘simplicity’ to the point of losing pragmatic use and speed. I’d say they’re pretty similar!

              1. 3

                they both are supported by a cult of personality

                Strong disagree, from someone who’s been moderately involved with uxn community previously. Who is the cult leader in this scenario?

            1. 0

              This site is more ads than content— is there a better source?

              1. 2

                Sorry I didn’t see ads due to uBlock origin. Tried finding other sources but all have adverts :(

              1. 22

                I don’t understand. Nowadays people don’t remember their ASCII by heart any more?

                1. 25

                  I genuinely hope this is a joke, because I’m 35 and been programming as a career for 12-ish years (including a 1-year paid internship) and I haven’t needed an ASCII chart more than a handful of times.

                  1. 12

                    Hahaha, I feel you.

                    I guess it’s always other people who deal with stuff like vtys and software flow control and fast parsers and keyboard drivers for us.

                    OTOH, man ascii. Typed in cool-retro-term for the best effect when teaching.

                    I believe it’s nice to start with unescaped in-band formats, then move on to the escaped ones, then fixed layout and finally TLV.

                    1. 5

                      man ascii

                      Did not know that was there. Nice!

                      1. 4

                        Ha, I just had to check to make sure \044 was what I thought it was when I saw it in a script yesterday.

                      2. 8

                        Being able to read hex and distinguish ASCII can come in handy in surprising places (especially during debugging).

                        1. 1

                          Recognizing SHIFT-JIS in hex has saved me days before.

                        2. 2

                          I’m sure it’s mostly a joke, but surely most developers know at least 1-3 ASCII codes by heart, especially full stack devs. When debugging HTTP-relates stuff you see stuff like %20 a lot

                          1. 1

                            Depends on what you work on, after many years of googling (no, I don’t have it ALL memorized) I started self-hosting one at an url I remember)

                          2. 2

                            Most people can’t read hexdumps anymore, and don’t have to thanks to improvements in tooling in recent years. We should be glad people don’t have to remember ASCII anymore :)

                            1. 2

                              Mine has rotted quite thoroughly out of my head. In the blue moon that I need to check, I just go pull up the table.

                              Most of the character problems I deal with these days involve Unicode instead, or rather, people not understanding Unicode and screwing it up.

                              1. 2

                                The last time I saw an ASCII chart printed in a book, it was published in the 80s (in fact, I think every computer book published in the 80s, at least in the US, had an ASCII chart somewhere in it). By the 90s, I think it was assumed ASCII was a known standard.

                                1. 1

                                  I slacked off back in the days and didn’t get around to actually learning it. Then we switched to Unicode and I just gave up.

                                  1. 6

                                    FWIW, all the ASCII knowledge is still applicable; the first 128 Unicode characters matches 7-bit ASCII, and UTF-8 encodes the values below 128 as just plain bytes with those values. So when looking at most text using the Latin alphabet, you can’t tell if you’re looking at ASCII encoded as bytes or Unicode encoded as UTF-8 even when looking at a raw hex dump.

                                1. 20

                                  Too bad this is not the default in Firefox. It should have been, since AMP was first introduced. I will never use Brave because of their BAT cryptocurrency scam.

                                  1. 6

                                    Any resources/info on it being a scam (other than “it’s crypto”, ideally)? I was under the impression that it was a helpful idea, but maybe I’m missing something.

                                    1. 4

                                      My understanding is that they crawled social media to find photos of the owners of websites in order to make it look like the website owners were part of their website donation project. If people then subsequently donated in the belief that the money would go to the people Brave claimed it would go to, but the site owners weren’t participating in the project, the money would be held in some escrow account for some time until Brave took the money themselves.

                                      They’ve also been really shady in increasingly making their browser pretend it’s just Chrome, making it impossible to block or inform visitors about the scam.

                                      Here’s pushcx’s comment about it when it affected lobste.rs: https://github.com/lobsters/lobsters-ansible/issues/45

                                      EDIT: And here’s Tom Scott’s twitter thread about it: https://web.archive.org/web/20181224160027/https://twitter.com/tomscott/status/1076160882873380870

                                      1. 2

                                        Hm. I’d heard of those things. I guess I agree that’s not a great impression. I can understand why they would make such a mistake in good faith. Then again, when you’re trying to “fix the web” you can’t steamroll the very content creators you’re trying to help. And even if it was the result of ignorance as they suggest, it certainly calls into question their diligence in less visible parts of their operation. Maybe they need to do more to assure potential users of their ecosystem that such oversights won’t happen again.

                                        In any case, I can understand better now why someone would hew towards Firefox rather than Brave. What a shame… Anyways, thanks for your reply!

                                    2. 2

                                      They’re also run by a bigot. Stay away.

                                      1. 3

                                        don’t you work for google? might be worth mentioning if you’re commenting on an article about how a competing browser is sidestepping one of google’s more evil recent projects

                                        1. 4

                                          I’m not speaking as a Google employee and I don’t work on Chrome. It’s a big company. I did work on other browsers for a long time in the Mozilla ecosystem, including working with LGBT ex-Mozillans when we looked around the Prop-8 donations to see if anyone we knew had made donations and saw Eich’s significant donations to deprive equal human rights to people he knows and worked with. My feelings about this have nothing to do with who I happen to work for at one time or other. I’m a huge fan of a broad ecosystem of browsers offering a variety of takes on the web - I spent half my career working on that vision - but don’t get your supposedly privacy focused browser from someone with a history of attacking the human rights of vulnerable people.

                                          1. 3

                                            If Brave’s technology is sound, it could always be forked. Similar to how people run de-Googled forks of Chrom(e|ium) to opt out of Google’s spying.

                                    1. 16

                                      I quit my job, so enjoying a lower level of stress, applying to new jobs, and practicing programming.

                                      1. 1

                                        You are brave! I couldn’t find myself quitting before an offer in hand.

                                        1. 12

                                          My boss was frequently verbally abusive and kind of unpredictable. I started to notice it was taking a pretty serious toll on my mental health, so I was willing to take the risk. Having no income sucks, but suicidal ideation is worse.

                                          1. 1

                                            I understand. At some point, your health is more important than the job, especially if the job is making you sick to a point you can’t enjoy your family’s company.

                                      1. 23

                                        Instead, please put the unit in the function name.

                                        (sleep-seconds 300)

                                        1. 5

                                          Too simple. People need to complicate and add yet another bit of complexity such as purpose created types, nammed parameters and whatnot that ultimately needs to be looked up in the documentation.

                                          Funny that the obvious solution isn’t even mentioned because people don’t even consider a design flaw from their all mighty favorite languages.

                                          1. 2

                                            I hate types

                                            1. 5

                                              And yet types exist whether they are declared or not, even in Lisp-y languages! Types are a characteristic of the universe we inhabit. I wouldn’t take my car to a hair salon to have the oil changed, and I know not to do this without actually trying it because the types don’t work out.

                                              1. 3

                                                Right. I’m working on a new essay on this but in short, I tried to design a dynamically typed lisp with maximal applicability of procedures—as in, “reverse” should be able to reverse a string, a vector, or a list, as opposed to having “string-reverse” or “vector-reverse” defined separately. I found that in order to implement that, I needed an isa-hierarchy of types (or, rather, derive an isa-graph from a tag cluster, kinda duck typing style). For example, strings, vectors, and lists are all “sequences”. So, in that sense, types are great.

                                                In order to not have to deal with types (as much) on the app level, I really do need to do them carefully (at the primitives level). So types aren’t useless. I still hate them though and languages that make it a point to do everything through types. Dependent types are the worst.

                                                I don’t wanna type annotate and I don’t wanna limit procedures to only compile on certain types. I don’t want the compiler to prevent you from taking your car to the hair salon.

                                                1. 3

                                                  APL achieves something very similar to what you are trying to do. Here’s a talk making the point (I think) that APL is so expressive, types would just get in the way.

                                                  Does APL Need a Type System? by Aaron W Hsu https://www.youtube.com/watch?v=z8MVKianh54

                                                  NB: I’m in general very type-friendly (as is the speaker it seems), but that just makes this perspective all the more interesting to me.

                                                  1. 1

                                                    I love APL ♥

                                                  2. 3

                                                    I don’t want the compiler to prevent you from taking your car to the hair salon.

                                                    But why wouldn’t you want that? The hair salon will do nothing useful with the car, and might even mess it up!

                                                    What if I call reverse on an integer? I’d love to find out that my mental model is wrong right after I type it (or, at worst, when I run the compiler) rather than when I run the code and get some inscrutable error in another part of my program because reverse silently did nothing with the value (or, even worse, treated the int as a bit string).

                                                    The fact that some languages have string-reverse and vector-reverse is more a function of the language and less a function of the types. You can easily define a generic reverse function in many languages and still get static types (and, if the language supports it, type inference so you don’t need to write out the types). There are also languages that support things like extension methods so that you can add interfaces to existing types.

                                                    1. 1

                                                      Sometimes I feel like this is, figuratively, an ergonomics issue. Some programmers feel more comfy with the kind of checks and balances you’re talking about and others (like me) hate them. I’m kinda glad that there are both kinds of languages.

                                                      We are veering in to off-topic because the thread is about sleep time units.

                                                      Let’s say I annotate 10 types. 2 of them find bugs, and then there are three or four bugs that weren’t related to types. Then I have done meaningless work 8 times, and put myself in a workflow or state of mind that make those three or four bugs way harder to find, all for the sake of finding two bugs (the kind of bugs that are often obvious on first run anyway). Instead, if I don’t have types, I check everything at the REPL and make sure it gives sane outputs from inputs.

                                                      Like, say I wanna make the procedure

                                                      (define (frobnicate foo)
                                                        (+ foo (* 6 7)))
                                                      

                                                      If I meant to type (* 6 7) but accidentally type (* 6 9), type annotation wouldn’tve caught that. Only testing can.

                                                      But why wouldn’t you want that? The hair salon will do nothing useful with the car, and might even mess it up!

                                                      Maybe they can drive around in the car and give haircuts all over town.

                                                      A lot of my best decisions as a programmer have been me realizing that the same procedure is much more general than I first thought (and then giving it a new, more general name). I like to type as I think, refactor and mold into the perfect parameter signature. (“Oh! I don’t need to pass in the list here, if I only pass the last pair, this function could share code with foo!”)

                                                      What if I call reverse on an integer?

                                                      My language converts it to decimal and reverses the digits. Useful for calculating probabilities for Unknown Armies.

                                                      I’d love to find out that my mental model is wrong right after I type it (or, at worst, when I run the compiler) rather than when I run the code and get some inscrutable error in another part of my program because reverse silently did nothing with the value (or, even worse, treated the int as a bit string).

                                                      So this is why humanity haven’t found the perfect language yet. Some people like different things. I’m not here to stop the type fest that’s been going on. Cool things might be invented from that camp down the line, it’s good that people are trying different things. If type inference could be made better so we don’t have to annotate…

                                                      1. 1

                                                        Let’s say I annotate 10 types. 2 of them find bugs, and then there are three or four bugs that weren’t related to types. Then I have done meaningless work 8 times, and put myself in a workflow or state of mind that make those three or four bugs way harder to find, all for the sake of finding two bugs (the kind of bugs that are often obvious on first run anyway).

                                                        Can you expand on this more? How do types make it harder to find non-type related bugs? In my experience, by completely eliminating an entire class of bugs (that aren’t always obvious catch-on-the-first run bugs, especially if you have a really nice type system!) it gets easier, not harder, to identify logic errors.

                                                        1. 3

                                                          As an analogy, overly relying on spell checkers can make some people miss things that are still legit spellings but are the wrong words in that particular sentence, like effect/affect.

                                                          But, it’s worse than that since (and I’m complaining about type annotation, not type inference) you need to enter the type info anyway. It’s “bugfinding through redundancy”. Sort of the same philosophy as “write a test for every line of code” but more rigid and limited. Of course reduntantly writing out what you want the function to accept and return is going to catch some bugs.

                                                          If you like this sort of type checking, you’re not alone. A lot of people love them, and ultimately there’s no need to argue. Time will tell if that style of programming does lead to overall fewer bugs, or at least does so for programmers of a certain taste, and if so, that’s fine by me. I’m not gonna take your ML away.

                                                          But as my “42 is odd” example shows, I’m not too happy with the whole “statically typed programs are Provably Correct” hype leading into the same hopeless dead end as Russell and Whitehead did a hundred years earlier.

                                                          Coming from C and Pascal, when I first discovered languages that didn’t have type annotations in the nineties (like awk, perl, and scheme) I felt as if I had found the holy grail of programming. No longer would I have to write out boring and obvious boilerplate. It was a breath of fresh air. Other people obviously feel differently and that’s fine.

                                                          For me, it seems that a lot (not all, but some) of the things a good type annotation system helps you with are things you don’t even need to do with dynamically typed languages. It also feels like with a type annotated language, there’s a catch-22 problem leading you to have to basically write the function before you write it (maybe with pseudocode or flowcharts) just so you can know what type signatures to use.

                                                          I felt that wow, a cons pair of car and cdr can express data in so many ways, I can just immediately write the actual logic of my code. Whereas when I worked as a Java dev (don’t worry, I’ve looked at modern type languages too, like Haskell) we had to slog through writing types (classes and instances), UML diagrams, wall full of post-its, architecture, ConnectionKeepingManagerFrobnicator.new() etc. With Scheme it was just, all that red tape just fell away. No need for pseudocode since I could just send whatever I was thinking into the REPL.

                                                          The type community loves the expression “to reason about the code”. Well, to me it’s a heck of a lot easier to reason about the code when it’s a fifth the size. (Sexps help too since it’s easier for me to grok a code tree than a linear sequence of unparsed tokens of code data.)

                                                          Obviously, type fans have had similar epiphanies but in the other direction, falling in love with static just like I fell in love with dynamic. And that’s cool. Let the deserts bloom. Humanity can’t be betting all of its eggs on my approach. I see the type craze as an experiment. One that might even be right. So please, go ahead.

                                                          I’m just really, really grateful that it’s not me who have to slog through it. I can sit under the cork tree sniffing dynamically typed flowers.

                                                          1. 2

                                                            Uh, wait, why did I get baited into writing all that when I see now that I already answered it in what you snipped out:

                                                            Instead, if I don’t have types, I check everything at the REPL and make sure it gives sane outputs from inputs.

                                                            Like, say I wanna make the procedure

                                                            (define (frobnicate foo) (+ foo (* 6 7)))

                                                            If I meant to type (* 6 7) but accidentally type (* 6 9), type annotation wouldn’tve caught that. Only testing can.

                                                            1. 1

                                                              hm, that doesn’t answer my question at all but it your longer post did, so thanks.

                                                              I think the point about “boilerplate” is pretty tired and not even true any more with how good type inference is nowadays. Yes, Java involved/involves a lot of typing. No, it’s no longer the state of they art.

                                                              It’s true that in the case where you use the wrong term that has the same type as the correct term, the typechecker will not catch this. Not having types is also not going to catch this. I’m going to see the error at the same exact time with both approaches. Having a REPL is orthogonal to having types, so I also often check my Haskell functions at the REPL.

                                                              I see the type craze as an experiment.

                                                              Calling an entire field of active research a craze is a little upsetting.

                                                              1. 1

                                                                I am complaining about annotated type systems specifically, which I clarified nine times. Inference type systems are fine.

                                                                Not having types is also not going to catch this.

                                                                The idea is that checking at the REPL will find it.

                                                                I’m going to see the error at the same exact time with both approaches. Having a REPL is orthogonal to having types, so I also often check my Haskell functions at the REPL.

                                                                Me too. Which made me feel like the whole type thing was a little unnecessary since I needed to do just as much checking anyway.

                                                                (As noted elsewhere in this thread, I’ve changed my tune on types a little bit since I realized I do need an isa-taxonomy for primitives. I.o.w. to get rid of types, I’m gonna have to define types.)

                                                                Calling an entire field of active research a craze is a little upsetting.

                                                                It’s more the whole dependent type / provably correct thing that’s a li’l bit of a craze, not the entire field of type research as a whole. As I wrote in my essay, types have a lot of benefits including serious performance gains, and that’s awesome. It’s the whole “it fixes bugs!” that gets a li’l cargo culted and overblown sometimes. Not by you, who do understand the limits of type systems, but by hangers-on and newly converted acolytes of typing.

                                                        2. 1

                                                          Lots of points from your arguments can be achieved by using generic types, and everything would work safely, giving the programmer quick feedback if the types work for the particular combination. No need to guess and check in the runtime.

                                                          My language converts it to decimal and reverses the digits. Useful for calculating probabilities for Unknown Armies.

                                                          So what would be the output of 2.reverse() * 2?

                                                          1. 2

                                                            Four.

                                                            1. 1

                                                              I’m wondering if that would also be the case with "2".reverse() * 2. Because if the output would be 4, then I’d wonder what would be the output of "*".reverse() * 2 would be. I hope it wouldn’t be **.

                                                              No matter what the answers are, I’ve already dedicated a lot of time to decode how some basic operations work. With types, I would have this information immediately, often without needing to dig through the docs.

                                                              1. 1

                                                                4 and ** respectively.

                                                                1. 2

                                                                  All kidding aside, the idea isn’t to overload and convert but to have a consistent interface (for example, reversing, or walking, or concatenating strings and lists similarly) and code reuse. I’m not insisting on shoehorning sequence operations to work on non-sequence primitives. Which is why I already said I needed an isa taxonomy of primitive types.

                                                2. 1

                                                  So sleep(seconds: 1) needs to be looked up in documentation whereas sleep-seconds(1) does not?

                                                  1. 2

                                                    If you language only supports the second, then use the second which is perfectly clear. You would by no means be ina. Situation where lack of language features limit code clarity.

                                                    Notice that while parameters have names in most languages, in many of them you can’t include the name on your code but rather need to pass them in order.

                                                3. 2

                                                  this way makes the most sense to me, at least for sleep

                                                  1. 1

                                                    It used to be a common sense that sleep uses seconds, until other languages not following that.

                                                    1. 5

                                                      That’s not how common sense works!

                                                  1. 44

                                                    the stories that could be told about the machines that run manufacturing plants. It’s great because everything is prod and everything will do horrible things if you fuck up. sometimes you are fixing something on a kiln 3x the size of your house and it breaks and you melt a couple thousand bricks, and sometimes you get told “yeah don’t worry about the puddles of acid on the ground we’ve neutralized them”.

                                                    1. 25

                                                      Please write a newsletter, and subscribe me to it.

                                                      1. 2

                                                        Same

                                                    1. 2

                                                      being happy again, applying to jobs. Gonna do some home brewing maybe

                                                      1. 6

                                                        The problem? Many of the programming ligatures shown above are easily confused with existing Unicode symbols

                                                        But existing Unicode symbols are already confusable with each other. The article also doesn’t explain why this is a problem.

                                                        1. 9

                                                          It seems to me that you are saying ‘there is already some ambiguity, this is a problem, why not add more ambiguity’. Seems like a question that answers itself.

                                                          I agree with most of the comments here that no one should be telling other people how to render their code to their own eyes, and no ligature settings are encoded in the source meaning it a completely individual choice with no consequences for others.

                                                          I also agree with the article that it is a terrible idea and you will never persuade me to allow ligatures anywhere near my IDE. I am also one of those strange people who hate wysiwyg editors of all kinds and avoid using them whenever possible so maybe I am just idiosyncratic. But I find when communicating with a computer, that precision is paramount and any ambiguity is dangerous.

                                                          Having said that I am interested in the idea mentioned above “when it sees things like || or &&, replaces them with a bolder ligature version to make them stand out in code”. This is a use for ligatures that deserves consideration. Don’t change my symbols, but highlighting certain sequences could be very handy.

                                                        1. 1

                                                          Haskell is great, except for all the monad transformer stuff. That’s all an absolute nightmare. At this point, I just don’t really see a reason to use it over Rust for writing practical (i.e. non-research) software. Rust has the most important pieces from Haskell.

                                                          1. 12

                                                            My experience with monad transformers is that they can offer a lot of practical value. There’s a little bit of a learning curve, but I think that in practice it’s a one-time cost. Once you understand how they work, they don’t tend to add a lot of cognitive burden to understanding the code, and can often make it easier to work with.

                                                            I do like some of the work people are doing with effects systems to address the down sides of monad transformers, and eventually we might move on, but for a lot of day to day work it’s just very common to end up doing a lot of related things that all need to, e.g. share some common information, might fail in the same way, and need to be able to do some particular set of side effects. A canonical example would be something like accessing a database, where you might have many functions that all need to access a connection pool, talk to the database, and report the same sorts of database related errors. Monad transformers give you a really practically effective way to describe those kinds of things and build tooling to work with them.

                                                            1. 8

                                                              What’s wrong with “all the monad transformer stuff”?

                                                              1. 3

                                                                Monads are mostly complexity for the sake of being able to imagine that your functions are “pure”. I have not found any benefits for such an ability, besides purely philosophical, at least in the way most functional programming languages are built. There are better ways, that can forgo the need for imagination, but the functional programming crowd doesn’t seem to find them.

                                                                1. 15

                                                                  Monads are for code reuse, they’re absolutely, completely, not at all about purity.

                                                                  1. 3

                                                                    I have not found them any good for that use case either. The code I’ve seen usually ends up as a recursive monad soup, that you need to write even more code to untangle. They can work well in some limited contexts, but those contexts can often work just as well using other programming constructs in my opinion. Limited code reuse in general is a problem with many half-assed solutions that only work in limited contexts, for example inheritance, DSLs, composition(the OOP kind), etc. Monads are just another one of them, and honestly, they are just as, if not more easy to overuse as the other solutions.

                                                                    1. 9

                                                                      I do not understand this perspective at all. traverse alone saves me an astonishing amount of work compared to reimplementing it for every data structure/applicative pair.

                                                                      1. 2

                                                                        The reason you need traverse at all is monads. It’s all complexity for the sake of complexity in my eyes.

                                                                        1. 5

                                                                          Not at all. traverse works for a far wider class of things than just monads. And even if a language didn’t have the notion of monad it would still benefit from a general interface to iterate over a collection. That’s traverse.

                                                                          1. 3

                                                                            general interface to iterate over a collection

                                                                            So, a for loop? A map() in basically any language with first-class functions?

                                                                            Anyways, my comment about needing traverse at all is in response of needing to reimplement it for many different data structures. The problem I see in that, is that the reason you get all of those data structures is because of Monads. There a lot less of a need to have such a function when you don’t have monads.

                                                                          2. 3

                                                                            The reason you need traverse at all is monads. It’s all complexity for the sake of complexity in my eyes.

                                                                            How would you write, say,

                                                                            traverseMaybeList :: (a -> Maybe b) -> [a] -> Maybe [b]
                                                                            traverseEitherBoolSet :: (a -> Either Bool b) -> Set a -> Either Bool (Set b)
                                                                            

                                                                            in a unified way in your language of choice?

                                                                            1. 3

                                                                              On a good day, I’d avoid the Maybe and Either types that are used for error handling, and just have good old exceptions and no need any traversal. On a bad day, I’d probably have to use traverse, because Maybe and Either, are monads, and create this problem in the first place.

                                                                              1. 1

                                                                                I think if you prefer exceptions to Maybe/Either then you’re sort of fundamentally at odds with Haskell. Not saying this in a judgmental way, just that “exceptions are better than optional/error types” is not how Haskell thinks about things. Same with Rust.

                                                                                Though, even in Python I typically write functions that may return None over functions that throw an exception.

                                                                                1. 1

                                                                                  I think if you prefer exceptions to Maybe/Either then you’re sort of fundamentally at odds with Haskell.

                                                                                  I’m pretty sure by just disliking monads I’m at odds with Haskell as it currently is. But do note, that not all exceptions are crafted equally. Take Zig for example, where errors functionally behave like traditional exceptions, but are really more similar to error types in implementation. A lot nicer than both usual exceptions, and optional/error types in my opinion.

                                                                                  Though, even in Python I typically write functions that may return None over functions that throw an exception.

                                                                                  It really depends if the function makes sense if it returns a none. If you’re trying to get a key from cache, and the network fails, returning a None is fine. If you are trying to check if a nonce has been already used, and network fails, returning None is probably the wrong thing to do. Exceptions are a great way to force corrective behavior from the caller. Optional types have none of that.

                                                                                  1. 1

                                                                                    I don’t understand why you say Zig error types “behave like traditional exceptions”. My understanding is that if I have a function that returns a !u32, I can’t pass that value into a function that takes a u32.

                                                                                    Similarly, I don’t understand the idea that exceptions force correctional behavior. If I have a function that throws an exception, then I can just… not handle it. If I have a function that returns an error type, then I have to specify how to handle the error to get the value.

                                                                                    1. 1

                                                                                      Yes, but essentially, you are either handling each error at the call site, or, more often, you bubble the error upwards like an exception. You end up with what I would call forcibly handled exceptions.

                                                                                      Not correcting some behavior leads to your program dying outright with exceptions. If you handle the exception, I’d say you are immediately encouraged to write code that corrects it, just because of how the handling is written. With functions that return an error type, it’s very easy to just endlessly bubble the error value upwards, without handling it.

                                                                                      1. 1

                                                                                        With functions that return an error type, it’s very easy to just endlessly bubble the error value upwards, without handling it.

                                                                                        If I have an Optional Int, and I want to put it in a function that takes an int, I have to handle it then and there. If I have an optional int and my function signature says I return an int, I must handle it within that function. The optional type can’t escape out, versus exceptions which can and do.

                                                                              2. 2

                                                                                I’d argue that these specific types are actually not very useful. If any error occurs, you don’t get _any _ results? In my experrience it’s more likely that we need to partition the successful results and log warnings for the failures. The problem with these rigidly-defined functions is that they don’t account for real-world scenarios and you just end up writing something by hand.

                                                                                1. 1

                                                                                  Haskell’s standard library is anything but rigid in my opinion. Take the specific case of “something that contains a bunch of (Maybe item).

                                                                                  • If you want a list of all items inside Just but only if there is no Nothing anywhere, you write toList <$> traverse l.
                                                                                  • If you want a list of all items inside Just, you can write fold $ toList <$> l.
                                                                                  • If you want just the first item, if any, you write getFirst $ fold $ First <$> l
                                                                                  • If you want the last item, if any, you can write getLast $ fold $ Last <$> l

                                                                                  These are specific to Maybe, especially the First and Last, I’ll give you that. But functions from the stdlib can be snapped together in a huge number of ways to achieve a LOT of things succinctly and generally.

                                                                                  1. 1

                                                                                    OK, this doesn’t actually answer my question. Say I have a stream of incoming data. What I really want to do is validate the data, log warnings for the ones that fail, and stream out the ones that succeed.

                                                                                    1. 2

                                                                                      Then use an API that’s designed for streaming processing of data, for example https://hackage.haskell.org/package/streamly

                                                                                  2. 1

                                                                                    I wrote up a few different operations on “collections of Maybe” or “collections of Either” in Haskell. The total number of lines of code required to express these operations using the standard Haskell library was around 12, including some superfluous type signatures. They cover all the cases in my other comment, as well as the “partitioning” you mention in your post. Here’s a gist:

                                                                                    https://gist.github.com/DanilaFe/71677af85b8d0b712ba2d418259f31dd

                                                                        2. 9

                                                                          Monads are mostly complexity for the sake of being able to imagine that your functions are “pure”.

                                                                          That’s not what they’re for. Monad transformers (well, the transformers in the mtl with the nice typeclasses) in particular let you clearly define what effects each piece of code has. This ends up being pretty useful: if you have some sort of monad for, say, SQL server access, you can then see from a given function’s type if it does any SQL transactions. If you attempt to do SQL where you’re not supposed to, you get a type error warning you about it. I think that’s pretty convenient. There’s lots of examples of this. If you’re using the typeclasses, you can even change the effect! Instead of reading from an actual db, you could hand off mocked up data if you use one monad and real db info with the other. This is pretty neat stuff, and it’s one of my favorite features of Haskell.

                                                                          I agree that they might not always be super clear (and monad transformers start to have pretty shit perf), but they’re not just for intellectual pleasure.

                                                                          1. 1

                                                                            Monad transformers (well, the transformers in the mtl with the nice typeclasses) in particular let you clearly define what effects each piece of code has.

                                                                            Slight correction: they usually let you define what classes of effects a piece of code has. This of course can range in abstraction, from a very specific SQLSelect to an overly broad, and not at all descriptive IO. One problem often seen with this, is that methods often combine several different effects to achieve the result, which leads to either having an obnoxiously large function signature, or having to merge all the effects under the more generic one, whether that be the more useful SQL if you’re lucky and the method only touches the SQL, or the frankly useless IO, in both cases loosing a big part of the usefulness of it.

                                                                            But the thing is, that you don’t need monads to achieve any of that anyways. If you represent external state (which the effects are meant to move away from you) as an input to a function, and the function outputs the same external state back, just with the commands it wants to do, a runtime can perform the IO, and bring you back the information on second function call. This of course might be somewhat counter-intuitive, as people are used for their main() function to be run only once, but it leads to another way of thinking, a one where you are more aware of what state you carry, and what external systems each function can interface with, as it lives straight in the function signature, only with an opportunity to hide inside a type to group several of them. This style would also naturally promote IO pipelining, since you easily can (and probably want to) submit more than one IO request at once. You can build the IO runtime on anything you want as well, be it io_uring, or a weird concoction of cloud technologies, if you provide your program with the same interface. It also brings the same testing possibilities, even slightly more, as making a golden data tests becomes ridiculously easy. More impressively, it brings the possibility of relatively easy time-travel debugging, as you only need to capture the inputs to the main function every function call to accurately replay the whole computation, and in part, enable to check some fixes without even re-doing the IO. I think this is a better way to move towards in functional programming, but I myself don’t have the time, or motivation in functional programming to push it that way.

                                                                            1. 2

                                                                              Classes of effects instead of effects is a distinction without a difference, right? I can define a monad typeclass that only puts things in a state and a monad typeclass that only takes things out instead of using StateT (in fact they exist and are called Reader and Writer), and I can get as granular as I’d like with it. The amount of specificity you want is entirely up to you.

                                                                              I agree that the IO monad is pretty frustratingly broad. You’re also correct that you don’t need monads to do this sort of thing. I’m having a little bit of trouble understanding your replacement. You mean a function with external state a and pure inputs b with result c should have the type a -> b -> (c, a), right? What would you do when you want to chain this function with another one?

                                                                              1. 1

                                                                                No. Your main function’s signature looks like a -> a. And a runtime calls it again and again, taking the actions the function specified in the output type that contains the external state objects, performing them, and putting the results back into the same objects. Your other functions as such grow in a similar manner, for example a function that takes an external resource a and a pure input b, to for example submit a write request, it would look like a -> b -> a. An important thing to note, that it only submits a request, but doesn’t do it yet. It would only be performed once the main function ends, and the runtime takes over. As such, you couldn’t do reading as trivially as a -> b -> (a, c), as you cannot read the data out while “your” code is running. This isn’t great for usability, but that can in large part be solved by using continuations.

                                                                                As a side note, I don’t particularly enjoy chaining. It’s another solution that is only needed because monads make it appear that the function isn’t performing IO, when it’s more useful for you to think that it does. With continuations, you could just make this look like several function calls in a row, with plain old exceptions to handle errors.

                                                                                1. 2

                                                                                  This seems far more complex than using monads to me, but different people think in different ways. I don’t know what you mean by you don’t enjoy chaining— you don’t like sequencing code?

                                                                                  1. 1

                                                                                    I like sequencing code, but I don’t enjoy sequencing code with monads, since monads force the sequencing of code they touch to be different, just because they are monads.

                                                                                    1. 2

                                                                                      Can you provide an example of monads changing the way you sequence code? That’s one of the major benefits of do-notation in my mind: you can write code that looks like it is executing sequentially.

                                                                                      1. 2

                                                                                        The do-notation is the problem. Why would sequencing functions that do IO would need to be different from sequencing functions that don’t? IO is something normal that a program does, and functional programming just makes it weird, because it likes some concept of ‘purity’, and IO is explicitly removed from it when the chosen solution are monads.

                                                                                        1. 2

                                                                                          Because functions that do IO have to have an order in which they execute. The machinery of a monad lets you represent this. I don’t care which side of (2+2) + (2+2) executes first, but I do care that I read a file before I try to display its content on screen.

                                                                                          1. 1

                                                                                            In the general case, you don’t care about the order the IO executes as long as you don’t have any dependencies between it. multiply(add(2, 2), 2) will always perform addition first, multiplication second, just like displayData(readFile(file)) will always read the file first, and display the data second. Compiler will understand this, without needing to distinguish the functions that do IO, from those that don’t. In the few cases where you don’t have any fully direct data dependencies, but still need to perform IO in specific order, you then may use specific barriers. And even with them, it would still feel more natural for me.

                                                                                            1. 2

                                                                                              In the general case, it’s impossible to determine which code might depend on the other. A contrived counter example would be writing to a socket of program a, that itself writes to the socket of program b, and then writing to the socket of program b. The order here matters, but no compiler would be able to determine that.

                                                                                              In the few cases where you don’t have any fully direct data dependencies, but still need to perform IO in specific order, you then may use specific barriers.

                                                                                              Yes, these specific barriers are exactly what monads provide.

                                                                                              Can you provide an example of a monad restructuring how you want to sequence something? I’m very open to seeing how they fall short, I haven’t written Haskell in a long time (changed jobs) but I miss the structure monads give very often.

                                                                                              1. 3

                                                                                                Of course no compiler can determine all dependencies between IO. In other languages you don’t need to worry much about it, because in other languages the evaluation order is well defined. Haskell though, forgoes such definition, and with the benefits it brings, it also brings it’s problems, namely, the inability to easily order unrelated function evaluation. There is seq and pseq, but they are frowned upon because they break monads :). So the way the IO monad works is by introducing artificial data dependencies between each monad. This feels quite hacky to me. But do note that this is mostly a problem with Haskell, and many other functional programming languages that are full of monads could get rid of them without much change in the language semantics.

                                                                                                Monads don’t change how I sequence something. But they do greatly annoy me, by needing special handling. It’s like mixing async and non-async code in other languages - either you go fully one way, or fully the other. Mixing both does not work well.

                                                                                                1. 2

                                                                                                  seq and pseq are definitely not frowned upon!

                                                                                                  1. 1

                                                                                                    Monads don’t change how I sequence something.

                                                                                                    Then why did you say:

                                                                                                    I like sequencing code, but I don’t enjoy sequencing code with monads, since monads force the sequencing of code they touch to be different, just because they are monads.

                                                                                                    They also don’t need special handling. Do-notation is syntax sugar, but there’s nothing in Haskell that privileges monads outside of the standard library deciding to use them for certain things. They are just a typeclass, the same as any other.

                                                                                  2. 1

                                                                                    As a response to your edit: no, reading is still a class of actions. You can read a single byte, or you can read a million bytes, and those two are very different actions in my mind. Trying to represent such granularity in monads is difficult, and honestly, a waste of time, since you don’t need such granular control anyways. But this is mostly disagreements in definition at this point, so no need to discuss this further I think.

                                                                                  3. 1

                                                                                    Yeah, linear IO is a major motivator for my work on Dawn.

                                                                                2. 8

                                                                                  This does not match my experience using monads at all.

                                                                                  1. 1

                                                                                    Monads arise naturally from adjoint functors. Perhaps they are not obvious, but that does not mean that they are artificially complex.

                                                                                    It sounds like you vaguely disapprove of effects-oriented programming, but you need to offer concrete alternatives. Handwaves are not sufficient here, given that most discussion about monads comes from people who do not grok them.

                                                                                    1. 3

                                                                                      Monads arise naturally from adjoint functors. Perhaps they are not obvious, but that does not mean that they are artificially complex.

                                                                                      Such technobabble explanations are why I try to distance myself from functional programming. While technically correct, they offer no insight for people who do not already understand what monads are.

                                                                                      It sounds like you vaguely disapprove of effects-oriented programming, but you need to offer concrete alternatives. Handwaves are not sufficient here, given that most discussion about monads comes from people who do not grok them.

                                                                                      I do, in this comment. It might not be the most understandable, it might not have the strong mathematical foundations, and it definitely is wildly different as to how people usually think about programs. But I still think that it can offer better understanding of the effects your program does, besides giving a bunch of other advantages.

                                                                                      Also, I don’t disapprove of effects-oriented programming, it’s just that monads are a terrible way of doing it. I feel like there are a lot of better ways of making sure effects are explicit, my suggestion being one of them, effect handlers being the other one about which I learned recently.

                                                                                      1. 2

                                                                                        I looked this up and it seems that the idea that every monad comes up as an adjunction occurs, if you define a category based on that monad first. isn’t this totally cyclic?

                                                                                        1. 3

                                                                                          In many cases, the algebras for a monad will be things we already cared about. In fact, that was sort of the original point of monads – a way of abstractly capturing and studying a wide variety of algebraic theories together.

                                                                                          For example, if you’re familiar with the list monad, its algebras are simply monoids, and so its Eilenberg-Moore category is (at least equivalent to) the category of monoids.

                                                                                          There are other monads whose algebras would be groups, or rings, or vector spaces over a field K, or many others.

                                                                                          But I think Corbin was probably not referring to the way in which every monad comes from at least one adjunction (or two, if you also throw in the one involving the Kleisli category), but rather that if you already have adjunctions hanging around, you get a monad (and a comonad) from each of them in a very natural way. If you’re familiar with order theory by any chance, this is a direct generalisation of how you get a closure operator from a Galois connection between partially ordered sets.

                                                                                          This entire discussion is almost completely irrelevant to someone using monads to get programming tasks done though. As an abstraction of a common pattern that has been showing up in combinator libraries since the early days of functional programming, you can fully understand everything you need to know about it without any of this mathematical backstory.

                                                                                          Why we recognise the monad structure in programming is mostly not really to be able to apply mathematical results – maybe occasionally there will be a spark of inspiration from that direction, but largely, it’s just to save writing some common code over and over for many libraries that happen to have the same structure. Maybe monad transformers take that an additional step, letting us build the combinator libraries a bit more quickly by composing together some building blocks, but these would all still be very natural ideas to have if you were just sitting down and writing functional programs and thinking about how to clean up some repetitive patterns. It would still be a good idea even if the mathematicians hadn’t got to it first.

                                                                                    2. 2

                                                                                      It’s completely opaque to me how to get them to do what I need them to do. I found myself randomly trying things, hoping something would work. And this is for someone who found Rust lifetimes to be quite straightforward, even before NLL.

                                                                                  1. 6

                                                                                    I asked for a raise at work and was told that I am “useless” and a “net drain on the company” and that it was an insult for me to ask. Which, even if those things were true (I personally think they’re not), that is absolutely not something you say to an employee lol. They didn’t fire me so I must not be useless, at least, but I will be applying to new jobs starting tomorrow.

                                                                                    And they won’t be getting two weeks notice, lol.

                                                                                    1. 1

                                                                                      Damn, if you can afford to, you should leave immediately IMO. Screw that shit, nobody gets to talk to you like that, it doesn’t even matter if they’re right or not.

                                                                                      1. 2

                                                                                        There’s a lot more to complain about. The boss accusing a coworker who wasn’t present of having dementia, calling the police on the last person who quit, etc. I’m getting out of there ASAP, but I feel for my coworkers who have to stay.

                                                                                    1. 2

                                                                                      using my 2 terms of community college japanese (and a dictionary) to translate a massive pile of comments for code that runs in a huge factory.

                                                                                      1. 21

                                                                                        I use proprietary software for work. It has great features, like forcibly mangling SHIFT-JIS comments into Window-1252 with no way to change my encoding. Or features like bizarre, fucked up proprietary file formats that are impossible to diff with git unless you pay $250, per head, per year, for their “git integration” license. Or really, really cool features like making breaking changes every sub-release of the ide/language, and then recommending that you use a VM to keep your old version around because they also couldn’t figure out how to let you use choose which version you wanted.

                                                                                        I would rather not use proprietary software for development.

                                                                                        1. 3

                                                                                          So there’s no open-source replacement for this software?

                                                                                          If there is, and your employer doesn’t want to use it, how about trying to find a new job that does?

                                                                                          1. 6

                                                                                            No, there isn’t any open source tooling in industrial automation. Most factories have a set of PLCs they bought in the 90s, and you need to buy that brand’s IDE to do work on that machine. So mitsu PLCs require you to hunt down a copy of GX Developer (and you better hope said copy is a Japanese one if you’re working in a Japanese plant or else you’re fucked), wago PLCs require their ide, and so on.

                                                                                            1. 1

                                                                                              opcfoundation.org ?

                                                                                              1. 2

                                                                                                OPC mostly encompasses data sharing from PLC to PLC or PLC to scada system, right? And typically, most factories use the proprietary system: MELSECNET for Mitsu machines, can’t remember what the other ones are called. There is a standard for languages that a PLC should support: IEC 61131-3, but not every manufacturer follows the standard.

                                                                                        1. 1

                                                                                          But it requires such a level of competence in math and physics

                                                                                          is this true? I know the book starts with Newton’s method of square roots, but it’s not tasking you with deriving the formula, it just asks you to implement it. And where does physics come in?

                                                                                          1. 1

                                                                                            Fairly lengthy equipment install on site, as well as setting up some SCADA stuff at another location.

                                                                                            1. 1

                                                                                              Going back to work after getting cleared of covid. I struggle with staying on task at home (I tend to just sleep instead of being productive) so this should be alright.

                                                                                              1. 6

                                                                                                Usual stuff since long time:

                                                                                                a decade old ThinkPad W520 filled with following software:

                                                                                                • FreeBSD
                                                                                                • ZFS with ZFS Boot Environments
                                                                                                • openbox
                                                                                                • tint2
                                                                                                • dzen2
                                                                                                • xterm
                                                                                                • caja
                                                                                                • mpv
                                                                                                • firefox
                                                                                                • geany
                                                                                                • plank
                                                                                                • deadbeef
                                                                                                • xlockmore
                                                                                                • automount
                                                                                                • beadm
                                                                                                • network.sh
                                                                                                • feh (for desktop background)
                                                                                                • xmodmap + xbindkeys (for mouse/keyboard shortcuts)
                                                                                                • redshift (blue light spectrum suppress)

                                                                                                Details of the setup here:

                                                                                                Regards.

                                                                                                1. 1

                                                                                                  Desktop background looks very disco elysium-y, what’s the source?

                                                                                                  1. 1

                                                                                                    Its this one:

                                                                                                    … but I am not able to track it down (with TinEye for example) to the original source.

                                                                                                    1. 1

                                                                                                      That’s an excellent game. Play it if you have not. It’s a choose your own adventure story game about a detective solving crimes with just a dash of DnD skill checks.

                                                                                                  1. 2

                                                                                                    The awful “jittering” of everything in PS1 has nothing to do with “subpixel rendering” it’s because textures aren’t perspective corrected, and it’s awful. Does anybody actually think it’s a desirable target to recreate?

                                                                                                    1. 9

                                                                                                      Well… there’s “technically desirable” and “artistically desirable”.

                                                                                                      When the PS1 came out this was more or less state of the art in terms of real time 3D rendering for consumer devices and everyone with stakes in the game could agree that it was awful and that the next generation of real time 3D renderers should not suffer from this problem. It’s definitely not technically desirable, as in, if what you’re looking for is to render the most life-like images you can, it’s a really bad idea.

                                                                                                      However, if what you’re after is to capture that feeling of playing PS1 at a friend’s house after school, or to paint contemporary themes with 1994 brushes, or anything of the sort, then it absolutely is a desirable target to recreate. Nostalgia is the most obvious reason but it’s not just nostalgia – we enjoy, say, medieval art, and modern drawings in medieval style, (hopefully) without being nostalgic for the pre-antibiotic times of warring petty barons and serfdom.

                                                                                                      (Full disclosure: some of the retro stuff I write is commercial so there’s always the riskt that I’m deliberately bending facts so as not to be out of a job ;-) ).

                                                                                                      1. 2

                                                                                                        It gives some of us a nice nostalgic feeling

                                                                                                        (He addresses texture mapping a bit further down)

                                                                                                        1. 1

                                                                                                          the game Ultrakill replicates it and it looks alright. I’ve also seen many horror games replicate it because of the weird, praecox feeling you get when textures start moving and wobbling on you.

                                                                                                        1. 3

                                                                                                          I really don’t mean this in a dismissive way at all. But I think this:

                                                                                                          Mike Rosulek is a cryptographer and associate professor in the School of EECS at Oregon State University. He has taught cryptography for over 12 years.

                                                                                                          is not a good biography. When deciding whether The Joy of Cryptography is likely to be worth reading, it would be more helpful to see examples of what the author has built and how it has been used. There has been a great deal of uninteresting cryptography instruction over quite a bit more than the past 12 years. While the title and school are certainly distinctive, I believe more specifics are needed to make the activity “has taught cryptography” worth reporting.

                                                                                                          A biography that conveys more information about the author’s background than that milquetoast blurb would make me more likely to pick this up and read it.

                                                                                                          1. 3

                                                                                                            What does building things have to do with pedagogy? I’ve met prolific developers who were horrible teachers and great teachers who hardly ever wrote code. The textbook is also focused on cryptography theory, not practice, which is much less “building things” and much more “writing proofs”, which I can assure you the author has done a lot of.

                                                                                                            1. 1

                                                                                                              I’m sure it’s just the lens of my own experience, coupled with the fact that I’m reading and posting on a site where the topic is computing as opposed to mathematics, that caused my mind to jump to applications of cryptography as opposed to its theoretical basis. The fact that the only biographical fact presented is that the author is a CS professor at an engineering school probably contributed to that, too. That said, if I edit my request to be “examples of what the author has proven” as opposed to “built”, I think it stands pretty well.

                                                                                                              If I see a book or a paper about cryptography theory with a very general title and a list of generic topics in the table of contents from, say, Adi Shamir, Alfred Menezes, Ralph Merkle, or Ron Rivest, I can make a pretty good guess about whether I’m interested thanks to familiarity with the author’s work.

                                                                                                              With an unfamiliar author, I scan the preface and the bio first to see if it’s likely worth setting aside time to read. On this book, the preface tells me that this book is about provable schemes for maintaining confidentiality, authenticity and integrity. The bio tells me the author is a teacher.

                                                                                                              My suggestion was simply to tell why it’s worth reading this author’s take on these very well-tread topics. I clearly obfuscated that by choosing the word “built”. That was unintentional.