1. 4

    Personally, I’ve never liked the advice that writing obvious comments is bad practice—probably because I write obvious comments all the time.

    This is fun and games while it is correct but when you run across a comment that is claiming the opposite of what the code does, what now?

    // Add a horizontal scroll bar
    newScrollBar = new JScrollBar(scrollBar, VERTICAL);
    

    What’s the correct behaviour? Should you fix the comment? Should you fix the code? Should you leave it alone if you’re not directly affected by it? With just the code the problem isn’t really there since there is one source of truth. It might not be correct but at least there’s no contradictions because the code does what the code says it does.

    The problem with comments is, that they’re non-executable, so the person changing the code changes the code otherwise the change will not happen. But will they remember to change the comment? Maybe, maybe not. This isn’t even a hypothetical case, I’ve seen cases where the comment claimed the exact opposite behaviour than what the code did.

    1. 5

      What’s the correct behaviour? Should you fix the comment? Should you fix the code? Should you leave it alone if you’re not directly affected by it? With just the code the problem isn’t really there since there is one source of truth. It might not be correct but at least there’s no contradictions because the code does what the code says it does.

      I’ve found those cases incredibly useful, because they tell me the code diverged. Something changed; why? Does other code assume the scroll bar is horizontal? Was that code switched when this snippet was switched to vertical? Does this code/comment divergence help me track down the bug I’m searching for?

      Without the comment I wouldn’t know that something interesting happened and wouldn’t even think to git blame it, but now I know that there’s historical information here.

      1. 3

        I’ve found those cases incredibly useful, because they tell me the code diverged. Something changed; why?

        Usually, because I slipped as I was typing the comment. I use the wrong word all the time when speaking and writing, and need either some testing or a careful reader to notice.

        There’s nothing insightful to be gained from my thinkos and brain farts: they’re also in my multi-paragraph expository comments, but at least there you usually have enough context to realize “oh, Ori is a sloppy writer, and clearly meant this”.

        1. 2

          The thing is: for the most part, 99% of the cases, this is because the code was changed but the comment wasn’t (very much according to Occam’s Razor) so what you get out of this is wasting your time with needless investigation of something that’s not actually a problem and then fixing the comment or just removing it outright.

          1. 2

            If you are certain the code is right and know the comment is wrong, then take 30 seconds to fix the comment to match the code and move on with your life. Not a big deal.

            If you are uncertain whether the code is wrong or the comment is wrong, then that indicates a hole in your understanding. That hole would exist whether or not the comment was there. So thats a useful indicator that you should investigate further.

            1. 1

              The comment makes understanding that line actively more difficult. If you’re reading the code for the purpose of coming to some initial understanding of a codebase then you’re going in with holes in your understanding and this inconsistent comment creates yet another hole.

              You’re suggesting that if I go to a random Github repo I’m not familiar with, start trying to read the code, and find a comment that is blatantly and objectively inconsistent with the code it’s attached to, that’s not actually a problem because if I just understood the codebase I’d know which to trust.

              You’re onto something there. That’s exactly the point: if context makes it clear which to trust, then you don’t need both, you just need the (correct) code. If we can make the assumption the misleading comment won’t matter because anyone reading it will know that the comment is wrong, then what is the comment doing there at all?

      1. 3

        I’m not what you’d call a Mac fan - I haven’t been a regular Mac user since ~ 2007 (Xeon based Mac Pro, and boy, was that a machine). But I still do use them from time to time (i.e. when clients issue them to me). So I’ve noticed some of the UX consequences of unification between macOS and iOS. And TBH they haven’t impressed me one jot.

        Take one small example: the Bluetooth menu. Used to be that I could just click anywhere in the enabled line to toggle Bluetooth. Now I have to mouse (well, trackpad, since we’re verbing things) over to precisely where the little slider-toggle is, and click that. This is a meaningful regression in usability, apparently solely so that the UI looks and feels more like iOS.

        I’d love to know what the driving factors are here. Because it feels like usability is being chucked under the bus for something. But it’s not clear to me what that might be.

        1. 3

          My more designer-y friends (and Marco Arment) angrily blame Alan Dye for many seemingly nonsense and objectively terrible UI/UX decisions.

          Seems like a senior designer is trying to make a name for themselves. It’s the only reason that makes sense to me.

          1. 13

            I know this marks me as a grumpy old man, but I miss the days of the Palm, Microsoft and Apple UX guidelines - for the most part, based on empirical user research and user-centric design.

            Some days it seems like the majority of UX research these days is to manipulate users, not empower them - A/B testing of dark patterns in conversion flows, for example.

            Maybe that’s me just being grumpy and old though ;) Or perhaps it’s a reflection of the fact that so often nowadays the user isn’t the customer.

            1. 7

              I get that people coming at user interfaces from a computer science perspective want to remove subjectivity from design decisions through science. But there are a few problems with empirical user research as the basis for design guidelines:

              1. The research does not meet scientific standards. Take a look at the work Nielsen Norman did in their heyday of the early 2000s. Heat maps, A/B tests: they all looked impressive and science-y, but they had incredibly small sample sizes and drew conclusions about things like ideal layouts that the data did not justify.
              2. The research is often divorced from context. People expect user interfaces to look and behave a certain way based on their prior experiences with technology. As technology changes, so do their expectations. Think, for example, about the proliferation of viewport sizes. Remember when almost everyone was using either a 800x600 or 1024x768 screen?
              3. You can’t empirically research your way into good typography or harmonious color palettes, either. Certainly, science can help us compare the legibility of fonts (which also have mutable, albeit slower moving expectations) or identify accessibility issues. But it can’t tell us how to set up the best grid for the information we’re trying to convey or what color palette best fits a brand.

              There will always be a subjective element to user interface design. It can be exhausting to keep up with design fashion. But every once in a while, there are designers who create simple but lasting designs that inspire multiple generations. The Vignellis covered this at length in their canon. User interface design needs such designers now, but they need to deeply understand the fluid nature of user interfaces running on a variety of touch and on-touch devices and driven by dynamic data. Much of today’s graphic design is still stuck in a print mindset.

              1. 1

                I’ll join you in feeling grumpy about that.

            2. 2

              I think the design changes were to make iOS apps look less awful on macOS.

              For some reason, Apple is desperate to bring iOS apps to Mac. They’ve tried Catalyst, which was a failure, mostly because iOS design language was too different from macOS’s. Apparently Apple thought it was worth to throw away the very refined Aqua for a thin iOS-like macOS skin just to “fix” this mismatch.

              Apple also brought iOS apps directly to M1 Macs. They’re still alien with bad UX, and the implementation is half-assed. And now Macs and iPads run the same hardware and bootloader.

              I suspect the current unpolished macOS design exists only because all of it is just a half-way step towards… I don’t know what. I hope they do :)

              1. 1

                For some reason, Apple is desperate to bring iOS apps to Mac.

                The number of iOS apps dwarfs the number of Mac apps. Convergence means instant and ongoing access to a ton of apps, and makes it more likely for people to buy a Mac. I think it’s pretty obvious that eventually iOS, iPadOS, and macOS will be unified into appleOS and run across all devices.

                As long as I can still get a shell prompt, I won’t really care…

                1. 3

                  Unfortunately I disagree, they’re pretty obviously trying to merge as much as the “backend” of the OS as possible, but I don’t think they will merge the frontends entirely for the forseable future.

                  Exploiting their monopoly on the app store makes them too much money to bring the macOS frontend features to iOS/iPadOS.

                  Limiting the MacOS frontend to the app store would be disastrous for developer market share.

                  Making app store exclusivity be the only difference would be begging for anti trust law to stop them from making money on the app store.

                  As a result they “need” to keep them separate for the foreseeable future, until something happens to upset the status quo. For example Epic winning big in their anti trust case, or some government regulator stepping up and doing the same.

                  1. 3

                    iPadOS was split from iOS quite recently and is diverging, so I’m not convinced.

                    1. 1

                      Only in terms of marketing. iPadOS and iOS are the same codebase with different features enabled/disabled. I think Apple would love it if macOS were the same way.

              1. 4

                Are there implementations of persistent/immutable collections in Swift, similar to what we have natively in Clojure or via libraries like Immutable.js in JavaScript or Paguro in Java?

                1. 5

                  If I take your meaning, yes. But the implementation is different from the way a Java class would have to enforce its own immutability. Collections in Swift are generally aimed at preventing shared mutable state. They have a way to provide mutability, but those mutations aren’t shared with other users of the collection.

                  Swift collections like Array are generally not classes but struct types, with value semantics. Assignment copies the value, not a reference to it. Mutations are disallowed through any constant variable, which is the idiomatic normal way to make any local variable or property. Behind the scenes there is a reference to a backing store, so that copies are cheap and mutations can grow the collection, and the value can remain a compile-time constant size. But mutations are still possible through a mutable variable, and in that case the backing store will be copied on write when it isn’t uniquely owned by just one copy already. So it’s a private mutation, not a shared one. The Array type didn’t have to assert immutability; rather it had to implement a copy on write pattern.

                  Finally, in the upcoming Swift Concurrency implementation of the actor model, only copyable data types can pass across actor isolation boundaries.

                  1. 3

                    I don’t think this is what was being asked, and I think the correct answer is “no, Swift doesn’t have persistent collections”:

                    The core property of persistent collections is that “mutating” operations are asymptotically as cheap as mutable collections, by retaining the unchanged parts instead of copying everything.

                    So if your COW collection (like array) copies everything on a change, it isn’t persistent.

                      1. 1

                        Yes, please read it.

                        1. 3

                          So if your COW collection (like array) copies everything on a change, it isn’t persistent.

                          Your claim is that “if your collection copies everything on a change, it isn’t persistent”. This is directly disputed by the wikipedia article where it states COW is a method for creating Persistent Data Structures. Inefficent, yes. But a method nevertheless.

                          1. 0

                            [citation needed]

                            1. 1

                              There is a naive scheme to make any data structure persistent. This scheme performs the operations exactly as they would have been performed in an ephemeral setting but before each update operation it makes new copies of all input versions. Then it performs the update on the new copies.

                              Kaplan, Haim (2001). “Persistent data structures”. Handbook on Data Structures and Applications https://cs.uwaterloo.ca/~imunro/cs840/Kaplan_persistent-survey.pdf

                          2. 1

                            Reading it, I think you’re pointing to this part:

                            This is an inefficient technique because the entire backing data structure must be copied for each write

                            But I’m not sure how being labeled an inefficient technique for persistent data structures makes it not a persistent data structure at all.

                            In Swift’s case, there’s an attempt to mitigate that cost, which is that copying only happens on write when the backing data structure is not yet uniquely owned, after which the new copy is uniquely owned, and further mutations do not copy again. In effect, what the programmer sees as a collection is a history snapshot of the collection. The backing structure of items is preserved not for every step of history, but for every step that some collection still has a handle to.

                            1. 1

                              Because it’s as if you called cutting the power cord to your workstation “garbage collection”.

                              Yes, technically all memory has been cleaned up, but everyone knows that this is not what people have in mind when using the term.

                              Wholesale copying the complete array on change is certainly not what people have in mind when talking about persistent data structures.

                              1. 1

                                Ha, ok. Well I don’t doubt you. It just seems like there are strict and loose interpretations of the term at play here. I’ll encourage you to contribute changes to that Wikipedia article since you’re familiar with the research.

                        2. 1

                          If I understand what you mean, in Swift there is a copy of the buffer, but it’s a shallow copy, not a deep copy. In that sense it doesn’t copy everything on a change. But there are two cases, and I wonder whether you’d call each case a persistent collection. Before a mutation of a collection whose backing store is not uniquely owned:

                          If the items are class objects, then the backing store of many pointers is copied. The objects themselves are shared.

                          If the items are value types, like integers, strings, collections, or algebraic data type values, then they’re stored inline in the backing store, and indeed they’re all copied up to but not past any reference property they contain. So mutating an array of sets, for instance, will copy the array’s backing store of many sets, but not the sets’ backing stores. Again those are shared.

                          1. 1

                            No, that’s not what is meant by persistent data structures. Here is an introduction to the topic with a few examples.

                            1. 2

                              I think I’m reading here that under lazy evaluation, the work entailed by preserving history across many mutations is reduced by evaluating once at the end. Retaining the unchanged parts is a matter of adding interstitial thunks through which you’d observe the result of changes, including undisturbed original items. I can see how that doesn’t involve a copy across the length of the structure, and I imagine the work is instead on the order of the number of mutations.

                              In Swift, the work entailed by preserving history across many mutations is reduced by copying once for the first local change, after which point the structure is uniquely owned and can be mutated in place. Swift also idiomatically discourages mutation in the first place. When the need arises, though, it will have to copy those N items.

                              Swift doesn’t pretend to be a functional language, it just points us that direction from an imperative starting line.

                              1. 1

                                Persistent data structures do not require lazy evaluation or being a functional language, see HAMTs and its usage as an example for that.

                                I think it’s fair to say that Swift simply does not offer anything in this regard.

                        3. 2

                          Interesting!

                          Could you explain what happens in Swift in terms of mutations and copies when we write something like this pseudocode:

                          var m = bigNestedMap
                          m["b"]["c"] = 2
                          
                          1. 2

                            This is more complicated than it seems :) First, for map (dictionary) type in Swift, subscript will return optional, thus, m[“b”][“c”] won’t compile. You can, however, do: m["b"]!["c"] = 2. In this case, if “b” exists, it will modify m such that m["b"]! will contain the new “c” key. If “b” doesn’t exist, it will panic. This works because m is mutable, and m["b"]!["c"] will make a mutating func subscript(key: String) { set { } } call, which can mutate m["b"]!.

                            To make it is easier in Swift in case “b” doesn’t exist, Swift support this syntax: m["b", default: [:]]["c"] = 2, it will create an empty dictionary in-place if cannot find with key “b”.

                            Note that this behavior is different if you do:

                            var m = bigNestedMap
                            var mb = m["b", default: [:]]
                            mb["c"] = 2
                            

                            In the above case, you are not making in-place mutating func call, hence, m won’t change.

                            (Actually, thinking about it again, I don’t think that I explained well why for your case, it will mutate m, this does better job at it I think: https://github.com/apple/swift-evolution/blob/main/proposals/0165-dict.md)

                            1. 1

                              Happy to. First, Swift subscripts are like computed properties in many languages: They have get and set functions that you implement. The difference from a computed property is that a subscript’s two functions take an index argument too. So a single subscript assignment x[1] = 2 is equivalent to a hypothetical x.put(1, 2). A subscript read x[1] is like x.get(1).

                              Subscript assignment on a struct is like any other mutating function on a struct: it’s allowed only if the struct value is in a mutable variable. That applies to both the major and minor levels here.

                              We can think of your example case as:

                              var m = bigNestedMap
                              
                              // Make a copy of m["b"], sharing its backing store using the copied reference within
                              var n = m.get("b") 
                              
                              // Replace n's backing store with a shallow copy if it is not uniquely owned by n, then replace its item "c" with 2
                              n.put("c", 2)
                              
                              // Replace m's backing store with a shallow copy if it is not uniquely owned by m, then replace its item "b" with n
                              m.put("b", n)
                              

                              In the end, the number of collection backing stores has either increased by zero, one, or two depending on whether anybody else still has a copy of the originals’ backing stores.

                              If m’s backing store was copied, then its items were shallow copied. Being collections, they each share their backing stores with the items in the original backing store of m.

                              I’ve pretended the optional nil case doesn’t exist just to keep it simple. Dictionaries use optionals for the result of a read, but arrays just bounds-check and crash. Maybe this example is more accurate if you imagine it’s the Array type instead.

                              As you would guess, this is just a naive implementation and optimizations are possible, such as the detection of unique ownership (perhaps bigNestedMap is a local that’s never used again). But in general, mutation should only affect your own view of the collection.

                              1. 2

                                The behaviour you describe reminds me structural sharing via path copying (See here).

                                A couple of questions:

                                1. Is it exactly the same as path copying?
                                2. What do you mean by “backing store”?
                                3. You describe how structs work. Does dictionaries (aka hash maps) work in the same way?
                                1. 2

                                  Answering out of order:

                                  1: Yes, I’d call it pretty similar to that!

                                  3: Yes. Dictionaries are also structs in Swift, just like arrays and sets and other basic collections. All of them use the pattern I’m attempting to describe.

                                  2: A collection type, being a struct (a value type) and not a class (not reference type), is allocated inline with its owner, or on the stack if it’s a local variable. That allocation must be a fixed size regardless of adding items to the collection. So the struct will have a property that is a reference (a fixed size pointer) to a buffer on the heap where items are stored. That buffer is what I’m calling a backing store. Each array or dictionary or set will have one of those containing its items, and when the collection is passed around, the struct value containing the reference is copied but the buffer is therefore shared. Only when a mutation would alter a buffer that’s referenced by more than one struct value is the buffer copied. That’s a shallow copy, so if it’s for instance an array of ints, the ints will be copied then. If it’s an array of arrays, the child arrays will be copied but their buffers are again shared.

                                2. 1

                                  Swift subscripts are like computed properties in many languages: They have get and set functions that you implement. The difference from a computed property is that a subscript’s two functions take an index argument too.

                                  Rather weird btw, that they still use the [], unlike more modern languages…

                                  1. 2

                                    Do you have a language in mind you’re comparing to?

                          1. 12

                            Some context for Apple tech newcomers:

                            A pillar of Swift’s initial uptake was smooth interop with Objective-C, in which all of Apple’s application frameworks were written (most still are). “NSArray” and similarly-prefixed symbols are Objective-C classes from the Foundation framework — more or less ObjC’s standard library. In Objective-C, classes are reference types, and dispatch is always dynamic. Swift is performance-focused and has value type structs and enums, plus reference type classes. All of the above can have methods, and Swift will compile static, vtable, or dynamic dispatch depending on runtime possibilities.

                            Usually, only classes can be compatible with Objective-C for interop. But as distinct from Objective-C’s NSArray class, Swift arrays are structs. The same is true for other basic types like other collections and the string type. So for the standard library types, there has always had to be a plan for how that bridging between statically-called value types and dynamically-called classes can happen without developer effort. That’s goal 2 in this article. The underscore-prefixed symbols used to accomplish that are the standard library implementation, not something an app developer uses.

                            On Linux and Windows, where Objective-C was never part of the baseline, all the Objective-C interop logic is simply omitted by design. In the far future that may be true on Apple platforms as well. I believe Swift has C interop on any platform regardless of Objective-C.

                            The ArrayTypes have full value semantics via copy-on-write (COW)

                            “Value semantics” in the Swift world is as opposed to “reference semantics”. It just means “does it act like a value type or act like a reference type,” under situations like passing it to a function or saving it to a new variable. A class object is a reference, so you expect it to copy the reference and share the object. A struct is a value, so you expect it to make a unique copy, or at least behave like it did. But to have both growable arrays and known allocation sizes to hold them, a collection must back its storage with a reference. When a struct contains a reference, by default that will just get copied, which would share array storage and break value semantics. In order to let programmers think about arrays like they are values, the data should be copied. And to preserve performance under that constraint, it will only Copy On Write: When an Array gets a call that would mutate, it checks whether its backing store has only one owner. If not, it makes its own copy first. Then the mutation proceeds. Making a COW type is something a Swift programmer might have to do once in a blue moon, but usually the standard library has what you need.

                            This is a pretty good example of the compiler and standard library doing an awful lot for you, while not abstracting it so far away that you never learn it. A design principle of Swift is that you don’t have to keep Objective-C bridging or COW types or ARC memory management top of mind every day, but that you should understand them and have to think about them sometimes.

                            1. 5

                              Arrays being COW sounds like awfully dangerous performance footgun. Though considering that the language is largely used for macOS/iOS apps and nothing critical, it’s probably fine.

                              1. 4

                                It doesn’t cater to anything system-level yet, that’s right. The current intended use case is application-level stuff, they’re working on server stuff, and system level is an eventual goal. There are unimplemented plans for opt-in Rust-like ownership, for instance.

                                As for footgun severity, well, it does hide something from you in the sense that copies happen on some but not all mutations. But this copy is shallow, not deep, and the idiomatic norm is for everything to be a constant and not a variable, which prevents mutations and therefore COW operations. At the application level the iOS / Mac dev community has been pleased with the performance, and we’ll see how it goes as the language spreads to more performance-critical use cases.

                                1. 3

                                  At the application level the iOS / Mac dev community has been pleased with the performance

                                  Only insofar as they haven’t actually measured it.

                                  For example, I have seen several GitHub repos stating “we use Swift Codable, so it is fast”.

                                  Swift Codable is horrendously slow at around 10MB/s for encoding/decoding JSON on a fairly top-of-the-line 13” MBP/Intel. To compare, the actual SSD does 2 GB/s, and so is 200 times faster.

                                  I had an article series showing how to get around 20-30x faster speed using Objective-C.

                                  1. 3

                                    Your work looks promising for an app that heavily consumes JSON! I imagine the reason some of us haven’t focused on that problem is because we’re calling simple APIs, the objects are not huge, and decoding doesn’t show itself to be an outstanding bottleneck compared to the network call.

                                    In the first few years of Swift, everyone wanted to use its richer types in our model layers, and so our JSON-serialized domain models had to come along for the ride. Without Objective-C’s dynamism that was a tall order. There were a ton of libraries about it; none of them amazing. Like you wrote in your series, Codable was faster than those libraries, so it was fast compared to what early Swift devs had grown used to, but not compared to NSJSONSerialization producing plain untyped dictionaries. Really it was more of a standardization win than anything else.

                                    1. 1

                                      So we’ve come from “Swift is performance focused” first to “well, our users are pleased with the performance” (as long as they don’t measure) and finally to, essentially “well, performance isn’t really that important”.

                                      Hmm….

                                      1. 3

                                        My post was about context for people who are interested in how Swift arrays work. I’m not clear on why you’re picking a fight, but I’m not interested. Good luck with the book.

                              2. 4

                                Swift is performance-focused and has value type structs and enums

                                While Swift may be “performance focused” its performance is generally quite a bit worse than Objective-C. Sometimes amazingly worse, very rarely comparable or slightly better and usually noticeably worse.

                                And also very significantly less predictable, which is arguably even worse for real-world performance.

                                And of course Objective-C also has value type structs (and reference type structs) and enums, though admittedly the enums are nothing like Swift enums.

                                And you can use C arrays for those value types, and even have those allocated on the stack (making sure they don’t blow it) or inline. While there may be a way to create a Swift array where the underlying storage is guaranteed to not be heap allocated, I haven’t figure it out yet.

                                1. 3

                                  Safety is probably Swift’s first focus before performance. You can’t just drop down to C like ObjC could, and although you can write unsafe code you have to jump through significant hoops. The level of dynamism in Objective-C while still being so performant, even without any C escape hatches, was really something special. One thing I really miss is the speed of the compiler, though the safety and richer types feel worth it to me.

                                  Regarding the two languages’ structs and enums, yeah, they’re not the same beasts at all. Objective-C has what C has, while Swift uses the same keywords for two kinds of value-type objects that can have methods, conform to protocols, and participate in polymorphic dispatch. What I was trying to establish with that quoted line is the reason Swift uses multiple kinds of function dispatch depending on the situation.

                                  1. 3

                                    Yeah I’ve run into a lot surprising performance pitfalls with Swift. For performance sensitive code, I just switch to Objective-C now. It is as you said much more predictable, and IMO much easier to optimize being simpler than swift and having the option to easily fallback to C or C++ when necessary. That being said, for general purpose code I find the Swift’s robust type system a pleasure to use. I’ll take the performance tradeoff. Optionals and enums have been such a huge boost to the reliability and comprehensibility of my apps.

                                    1. 2

                                      For performance sensitive code, I just switch to Objective-C now

                                      Yeah, that’s pretty much what I recommend in my performance book.

                                  1. 1

                                    I never really got the understanding of why the usage of recursive functions (instead of loops). Sure, with proper tail recursion you won’t get stack overflow, but you are still pushing new stack frames for each iteration. Even if that is not so expensive, staying in the same frame is cheaper. My limited experience of using debuggers also point to keeping away from recursive functions.

                                    1. 7

                                      Sure, with proper tail recursion you won’t get stack overflow, but you are still pushing new stack frames for each iteration

                                      Isn’t that the point of tail recursion, to re-use the stack frame?

                                      https://en.wikipedia.org/wiki/Tail_call

                                      Tail calls can be implemented without adding a new stack frame to the call stack.

                                      As I understand it, the main downside is that in debugging you don’t see the recursion (because the frames aren’t there).

                                      1. 5

                                        As I understand it, the main downside is that in debugging you don’t see the recursion (because the frames aren’t there

                                        In which case you’re in exactly the same situation as if you’d used iteration, right? If you wrote the code as recursive then you have the option to turn off the tail-call elimination temporarily if it helps your debugging.

                                        1. 1

                                          Yes, I think the main difficulty more comes in when you have tail calls which are not necessarily recursive (same function), A calls B calls C, all in tail position and you won’t see B on the stack if you break in C.

                                          1. 1

                                            In that case A, B, and C could all have been labels in the same function, and the calls gotos. That’s what the generated machine code effectively is – which is more efficient than the CPU executing call/return each time.

                                            Yeah, it’s harder to understand in that optimised form. But with optimised tail-calls it’s possible to tell the compiler not to optimise temporarily, if you want.

                                        2. 2

                                          As I understand it, the main downside is that in debugging you don’t see the recursion (because the frames aren’t there).

                                          Yet you see the arguments to the call, thus showing you exactly how to replicate your bug without any extra steps

                                          1. 1

                                            Yes, but see comment above about non-recursive tail calls.

                                        3. 3

                                          It can be a fun and interesting puzzle, not something I’d normally do (unless it fit the problem). Also, some languages (such as Erlang, I believe) don’t have loops.

                                          1. 3

                                            Like someone else already mentioned, there are languages without iteration constructs (Erlang/Elixir are both entirely reliant upon recursion to express iterative constructs like loops, for/foreach, do/while, etc. This is intentional in those languages because there is no support for mutation (there are some ways to work around that, but at the syntax level mutation doesn’t exist), and the runtime provides tail-call optimization, so there is no runtime cost to tail recursive calls, even mutually recursive functions.

                                            On top of that, some algorithms are more elegantly expressed recursively, which can make reading the code much easier to understand. In Erlang/Elixir, which have rich pattern matching capabilities, the ability to break up a function into multiple clauses, each of which pattern match on the function arguments directly in the function head, mean you can neatly express the different cases of a recursive algorithm across a few clauses. For example, in Elixir the following expresses the algorithm for summing a list of integers:

                                            def sum(list) when is_list(list), do: sum(list, 0)
                                            
                                            # Base case, empty list
                                            defp sum([], acc), do: acc
                                            # List consisting of at least one element
                                            defp sum([n | rest], acc) when is_integer(n), do: sum(rest, acc + n)
                                            

                                            This is obviously a trivial case, but as you can see, each case of the recursive algorithm can be expressed in its own clause, which are pattern matched against the input in top-down order.

                                            1. 2

                                              There is no difference between tail-recursion and iteration wth respect to debugging. Recursion that is not tail-call optimised gives you more information for debugging than iteration.

                                              1. 1

                                                This sounds like premature optimization. I can’t think of a case when (even non-tail) recursion bit me wrt performance.

                                                1. 3

                                                  The performance of non-TCO can be fine, until it suddenly isn’t. For example, if you don’t control the input you may encounter StackOverflow errors. Last week my team tried to implement a max limit to the number of nodes a tree could have, and one of our test cases was a very, very deep tree that caused a StackOverflow in our initial (naive, non-tail-call optimised) recursive solution.

                                                  1. 1

                                                    Your problem is not that you used recursive code, it’s that you used a non-balanced tree.

                                                    If you’d used iterative code with a an explicit stack to keep track of your position in the tree you’d have exactly the same problem.

                                                    1. 1

                                                      You wouldn’t stack overflow with an explicit stack. Heap size is much larger than the max call stack size.

                                                      1. 1

                                                        You actually can, fairly easily. Say your graph has a loop, and you don’t detect that. Try putting the below YAML into http://www.yamllint.com and hit “Go” for example. (Please note I’m not criticising that site in particular. My point is that failing to detect loops is an easy mistake to make: I only had to try 3 online YAML parsers before I found one that doesn’t.)

                                                        a: &a [*a]
                                                        

                                                        I don’t know if that site uses a recursive or non-recursive solution, but I’d put good money on some kind of stack overflow happening with that input. And no amount of heap space will help your code avoid a stack overflow (eventually!) if you use the stack to track visited nodes in an infinitely deep tree.

                                                        (Edit: extract YAML to its own code block for clarity)

                                                      2. 1

                                                        I think you missed the point of my comment: I was trying to give a concrete example of where a TCO recursion would be preferable (performance wise) vs a non-TCO one. You should have used a balanced tree isn’t always an option; especially when the input is user-defined, as I already mentioned it was. As it happens we didn’t really need a stack, as we were only counting nodes to verify the tree didn’t have more nodes than we wanted to allow. And as we’re using lisp, a recursive solution would be the most idiomatic.

                                                        1. 2

                                                          You can’t TCO a tree walk – at least not both subtrees.

                                                          If you know in advance which subtree is bigger then you can recurse on the smaller one and then TCO on the bigger one, and this limits max stack depth to less than log2(N). But you often don’t know that in advance.

                                                          1. 1

                                                            You can’t TCO a tree walk – at least not both subtrees.

                                                            Ah, dang. Thanks for pointing this out.

                                                1. 14

                                                  I may have missed something, but what’s the problem with just having multiple accounts? I get that accounts tied to phone numbers are annoying, but that’s a problem with or without phone numbers (I for example would like to have no phone at all). The solution seems to be making accounts cheap (eg. via cryptography) that can be mapped on to complex identities, instead of basing everything on a complex system.

                                                  That being said, in most cases identities/accounts are superfluous, and shouldn’t exist in the first place.

                                                  1. 10

                                                    Not the author, but my own biggest challenge is that most services make multiple accounts difficult and/or expensive to use in a lightweight fashion. In short, they’re a pain.

                                                    I.e., the clients for most services don’t support being signed into more than one account at once; it’s not supported to run more than one active client at once; and if I’m running multiple clients, they’re really resource heavy. When I’m using multiple accounts, I usually want to use them more or less concurrently. I’d like to have just one client open, and toggle between accounts at will.

                                                    Also, even when a phone number isn’t required, many services also require that each account be associated with some external resource like an email address, which means I need to manage those as well. (Some services even collapse plus-addresses, so I have to actually create separate email accounts, or do weird forwarding stuff, or whatever.)

                                                    1. 7

                                                      Some services even collapse plus-addresses

                                                      Ugh, that’s downright evil.

                                                      At least with your own domain you don’t have to use the plus scheme, you can make whatever scheme you want :)

                                                      1. 4

                                                        But then you have to use your own domain :D

                                                      2. 3

                                                        I think it’s obvious to everyone, that the system of accounts is broken, because it has been constructed in such a round-about way, on top of systems that weren’t meant for it, but are expressive enough for implement some kinds of identities. Email, for example, has been reduced to a (questionable) foundational-identity, that most people don’t even bother to use as Email, because all they get “click-here-to-confirm” links at best, and outdated notifications at worst. But for most clients, switching between identities is pretty easy, as it’s just changing what’s in the From field (eg. I automatically detect if a To, Cc or From field is from a university address, and let Emacs replace the To field for me).

                                                        But most “platforms” have to re-implement everything from the ground up, accounts, passwords, backup systems, systems to reset passwords, usernames, etc. Just consider how a problem as simple as sending a text message has resulted in so many mutually incompatible solutions. As such, it’s not a surprise that systems of identification don’t cover all use-cases.

                                                        Generally: The more I think about it, the more I believe that most of these problems should be solvable on a “lower” level, instead of making the towers we have built on top more and more complicated. Communication and identities should be primitive concepts in networked systems, that then ideally should be cheap and interchangeable. But all of this are just unfinished ideas.

                                                      3. 14

                                                        Here is a screenshot showing how many instances of Discord I have open right now: https://i.imgur.com/6yitn61.png Discord’s UI doesn’t easily allow for creating and using multiple accounts. I have to run things like Rambox that make me end up dedicating about 5 GB of ram to that whole mess in addition to my primary account (Yes Discord really uses that many resources). This is even worse on my iPad because I can’t just have multiple accounts active at once.

                                                        I currently have to keep track of over 12 email addresses between the various separations involved.

                                                        in most cases identities/accounts are superfluous, and shouldn’t exist in the first place

                                                        They are superfluous to you because you haven’t experienced the kind of realities that would demand you to have thought about this. This is as useful to parents that want to have a social life while having children as it is to others like plural systems.

                                                        1. 18

                                                          I mean, I agree that discord is terrible, and it’s a tragedy that it has become as pervasive as it is. But I’m not sure what that has to do with my point? Maybe my other comment in response to @ajdecon clarifies what I am talking about.

                                                          They are superfluous to you because you haven’t experienced the kind of realities that would demand you to have thought about this.

                                                          I’m not sure how you came to this conclusion, but all I can say is that it is not true, and that my experiences with the problems you have enumerated, have led me to the opposite conclusion. Please do not assume that everyone who has a different stance is ignorant or inexperienced, it comes of as quite arrogant (this applies to your post and your comment).

                                                          Thank you.

                                                          1. 2

                                                            Discord’s terribleness is far from unique. The Google account switcher is basically the current best-of-industry on this problem, and it’s not exactly amazing..

                                                            1. 1

                                                              Not sure what makes you think that, but I found the ones in Reddit and Twitter far better.

                                                          2. 4

                                                            Interestingly, official Telegram clients have a very easy account switcher.

                                                            Even though Telegram is one of those phone-number-based messengers.

                                                            1. 2

                                                              Isn’t that a problem with Discord that is largely orthogonal to the identity problem? That is, why do you still need an identity-management system if Discord was super-low-resource-usage, allowed you to run multiple instances signed into different accounts, and let you use a single phone number/email address for multiple accounts?

                                                            2. 2

                                                              in most cases identities/accounts are superfluous, and shouldn’t exist in the first place.

                                                              Why? In what way? I can’t tell if you’re saying “people shouldn’t have multiple identities” or just “accounts on computers and websites are often not really needed”.

                                                              1. 2

                                                                The latter.

                                                                1. 2

                                                                  Um, really? “Extraordinary claims demand extraordinary evidence.” I can think of some valid nuanced points about identity and security you might be making, but on face value your statements seem obviously wrong. If for no other reason, shared systems need identity/accounts just to distinguish between people’s content in a situation without total implicit trust.

                                                                  1. 2

                                                                    Looking through my password manager a solid third of them are for random websites that I had to create an account with just to access some content or make a one-off comment or purchase. I think there is a good claim that a lot of times identity/accounts are unnecessary.

                                                              2. 2

                                                                The solution seems to be making accounts cheap (eg. via cryptography) that can be mapped on to complex identities, instead of basing everything on a complex system.

                                                                This just shifts the domain modeling problem from the system to the user. Users would end up having to keep a private dictionary of identities which they map to cryptographic identities. Managing a single cryptographic identity is difficult as it is, and shifting the burden of management to the user makes this even more difficult and error prone.

                                                                TBL’s Solid project envisions a system of identity providers whose some job it is to offer a UX to managing user identities, and I think this is an interesting solution. You pay/host (or let them mine your data) an Identity Provider that lets you manage multiple identities, and use that identity provider across the web.

                                                              1. 2

                                                                Now add Apple to this model, who work in none of those ways accused of being the “Silicon Valley” ways.

                                                                1. 2

                                                                  They’re not really a software company though, software is a means to an end to them - just like with “traditional” companies.

                                                                  Their main pillar is hardware and they try to shift to services, and the software they ship on their hardware isn’t great (basically living off the NeXT-inheritance from 20 years ago) and from what can be seen with their services, neither is it great there.

                                                                  1. 3

                                                                    The problem is that there are no true Scotsmen: no company is a software company. Facebook is an ad broker. Netflix is a media channel. Microsoft is a licensing company. Red Hat is a training company. It just happens that they each use software quite a bit in delivering their “true” business, just like Apple.

                                                                    1. 4

                                                                      Yeah, shipping the 2nd most popular desktop, mobile os and web browser is pretty trivial. Any “real” software companies could do it. All the tech has been there for 20 years after all.

                                                                      1. 2

                                                                        iCloud had a rough start (and even more so its predecessors .Mac, MobileMe, etc.) but it seems mostly rock-solid today and has an astronomical amount of traffic. A billion and a half active devices, I believe, with a large proportion using multiple iCloud services all day every day. I’m not saying Apple doesn’t have room for improvements in services, but “Apple is bad at services” is just a decade old meme at this point, IMO.

                                                                    1. 25

                                                                      The linked forum post by the author of ‘Return of the Obra Dinn’ is also very interesting.

                                                                      https://forums.tigsource.com/index.php?topic=40832.msg1363742#msg1363742

                                                                      1. 2

                                                                        Trying to stay motivated on my side project. Trying to monetize it has made it a lot less fun to work on and generally been stressing me out. There’s a new self-imposed pressure to put out features as quickly as possible. Probably a life lesson to be learned in this.

                                                                        1. 1

                                                                          Making something fun into a job sucks. I’ve been there. If you definitely want to monetize it, maybe htow someone else to work on it, then you can find a new side project to do just for fun.

                                                                        1. 7

                                                                          Blocking Netflix, YouTube and other streaming sites at home. Stopped me from mindlessly binge watching tv shows in the background. I still get distracted in other ways, but there’s something about TV that gets me hooked for days at a time.

                                                                          1. 2

                                                                            I do the same in my house. We use adguard home installed with home assistant. All news sites and social media sites are blocked during the day. The block turns off at 1900.

                                                                            To say it has changed my life is a huge understatement

                                                                          1. 5

                                                                            Albert Einstein’s Theory of Relativity — In Words of Four Letters or Less ⌘ https://www.muppetlabs.com/~breadbox/txt/al.html

                                                                            1. 2

                                                                              That is awesome. I don’t know how understandable it would be to someone without background knowledge in physics. But very impressive how much they were able to explain.

                                                                              1. 2

                                                                                That essay is very similar in philosophy to the Gödel-proof description mentioned in the article. Like Evans points out, it’s mostly written for people who already know what Gödel’s proof is. My essay has the advantage of being about Einstein’s relativity – a lot more people have a vague idea what relativity is, at least. (And of course it’s much longer than the Gödel essay. I actually started out intending it to be shorter, but I really did want to try to explain the ideas behind relativity, and so it wound up getting longer and longer.)

                                                                                1. 2

                                                                                  Back in 2011 I created an ebook out of the webpages so that I could read the essay on my ereader:

                                                                                  To be honest, I cannot remember how successful the conversion was.

                                                                                  They weren’t meant for public consumption, but now that you’re here…

                                                                              1. 7

                                                                                rsc on the “three approaches” seems like they ignored a lot of prior art; C# is a mainstream language that has actual reified generics for quite a while, to say nothing of what the FP community has.

                                                                                1. 9

                                                                                  The post you are referring to directly asks for help finding prior art. Also does C# style reified generics even make sense for Go? It requires a lot of runtime support.

                                                                                  https://research.swtch.com/generic

                                                                                  1. 7

                                                                                    But at least they decided to work with Phil Wadler in the end.

                                                                                  1. -1

                                                                                    Can anyone recommend some material describing concrete motivations for adding generics to Go? I’m aware of the abstract idea that you need generics in order to build data structures that work with different types, but is there a real-world setting where this is actually better than just copying code and doing s/type1/type2/g? My sense is that projects that use complex data structures almost always customize the data structures in a way that depends on the data type being stored.

                                                                                    1. 19

                                                                                      I hope it’s not that hard to imagine wanting different data structures than hash maps; maybe your problem fits better into a binary search tree for example.

                                                                                      Well, I for one usually don’t feel like implementing my own red-black tree, so I would like to just grab a library. That library will be much nicer to use if I can just make an RBTree<string, MyFoo>. I certainly wouldn’t want to copy/paste an int->string red-black tree into some file(s) and judiciously search/replace until I have a string->MyFoo tree (and then do the same when I need an int->float tree).

                                                                                      1. 0

                                                                                        That makes sense, but I am still looking for some grounding in actual programming practice. Is there a use of a red-black tree that would not warrant customizing it for the storage type? Or one where it would make sense to add a library dependency rather than copying the RB tree code?

                                                                                        1. 8

                                                                                          How do you write a library that provides a Red-Black tree that can in principle work with many different client types without generics? This isn’t a rhetorical question, I don’t know Go and I genuinely don’t know how you would implement this kind of library in Go without generics.

                                                                                          1. 6

                                                                                            Go’s sync.Map (concurrent hashmap) is an actual real world example of this, and it uses interface{}, akin to Java’s Object.

                                                                                            1. 25

                                                                                              Right, that’s a great example. Because it uses interface{}, it:

                                                                                              • Requires all keys and values to be heap allocated, leading to worse performance, worse memory usage, and worse memory fragmentation. Requiring two heap-allocated ints to store one value in an int->int concurrent hash map is unacceptable for many uses.
                                                                                              • Is less ergonomic, requiring a cast every time you want to use a value.
                                                                                              • Provides no type safety. (I imagine this one will be the least convincing to Go programmers, since Go generally expects the programmer to just not make mistakes)
                                                                                              1. 4

                                                                                                This brings me back to C++Builder 3 back in the 90s. To use a list, you had to create a class derived from a kind of TItem class to be able to store things. Why anyone would want to go back to that in productive code boggles my mind.

                                                                                                1. 1

                                                                                                  I’m using a sync.Map (for its concurrency support - I have many goroutines writing map entries, and another goroutine periodically ranging over the entire map to dump it to a json file).

                                                                                                  However I know the types I write to the map, I have no need for interface{}.

                                                                                                  Am I better off with a real typed map + using sync.RWLock/mutex/etc. directly (in a custom struct)? Performance-wise.

                                                                                                  1. 1

                                                                                                    I don’t know, you would have to benchmark or measure CPU or memory usage. The sync.Map documentation suggests that using a regular map + mutexes could be better though: https://golang.org/pkg/sync/#Map

                                                                                                    The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

                                                                                                    The Map type is optimized for two common use cases: (1) when the entry for a given key is only ever written once but read many times, as in caches that only grow, or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

                                                                                                    If your usage falls outside of the two use cases which sync.Map is optimized for, it would absolutely be worth looking into replacing your sync.Map with a regular map and a mutex.

                                                                                                    I suppose it becomes a question of which has the biggest performance penalty for you, heap allocation + indirection with sync.Map or lock contention with regular map + mutex?

                                                                                                    (Also, in most cases, this probably doesn’t matter; make sure you’re not spending a long time improving performance in a part of your code which isn’t actually a performance issue :p)

                                                                                                    1. 1

                                                                                                      Right - the code “just works(TM)” and it takes around 0.5 seconds to render the JSON file every minute (which I track with metrics just to be safe) so it should be fine to keep as is. This is just a for-fun conversation.

                                                                                                      or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

                                                                                                      I definitely remember reading this sentence and it made me choose sync.Map because it sounds like my usecase. But like you say if I don’t measure it’ll be hard to tell.

                                                                                              2. -1

                                                                                                I don’t know and I didn’t think you could. I’m asking for an example use of an RB tree where using a library would make sense.

                                                                                                1. 6

                                                                                                  Here is a popular Go RB tree implementation https://github.com/emirpasic/gods/ that uses Interface{} for the key and value types. Just search github for uses of it… With generics, users of this library would get greater typesafety.

                                                                                                  https://github.com/search?q=%22github.com%2Femirpasic%2Fgods%2Ftrees%2Fredblacktree%22&type=Code

                                                                                                  1. -2

                                                                                                    okay. except i don’t know how to search github for uses of it and your search link brings me to a login page :(

                                                                                                    1. 5

                                                                                                      To short-circuit this:

                                                                                                      At a previous job, I worked on a tool that started various services. The services had different dependencies, each of which needed to be started before the service. We wanted to be able to bring them up with as much parallelism as possible, or have a flag to launch them serially.

                                                                                                      A simple approach to doing this correctly is modeling the dependencies as an acyclic graph (if it’s a cyclic graph, you’ve got a problem — you can never bring the services up, because they all depend on each other). To launch them in parallel, launch each one that has its dependencies met. To launch them serially, topologically sort the graph into an array/list/whatever and launch them one by one.

                                                                                                      A generic graph implementation would be very useful, as would a topological sort that worked on generic graphs. With Go, you can’t have one that’s type-safe.

                                                                                                      Another great use case for graphs: visualizing dependency graphs! You can have an open source graph visualization library, build a graph of whatever it is you’re trying to visualize, and pass it to the library and get a nice visualization of the data.

                                                                                                      Graph data structures can be quite useful. Supporting generics makes them type-safe, so you catch errors at compile time instead of runtime. Some other examples of the usefulness of graphs:

                                                                                                      • Graphs of friends at a social network (I currently work at one, and we use generic graph data structures all over the place — graphs of people to people, graphs connecting people and photos they’re tagged in, etc)
                                                                                                      • Network topology graphs
                                                                                                      • Graphs of links between documents

                                                                                                      etc.

                                                                                                      And it’s not just graphs. How do you write a type-safe function that takes in a list of possibly-null items, and returns a new list with the nulls stripped out? How about a function that takes a map and returns the list of its keys? In Golang, the answer is always copy-paste or give up type safety. In languages with generics, you can trivially write these functions yourself if they’re not in the standard library.

                                                                                                      1. 1

                                                                                                        thanks, this is a good motivating example.

                                                                                                        1. 1

                                                                                                          Huh. It had not occurred to me that github search would require a login.

                                                                                              3. 11

                                                                                                To turn the question around, why would you want to manually copy/paste code all over the place when the compiler can do it for you? And while I personally think “DRY” can be over done, not having the same (or very similar) code copy/pasted all over the place seems like a big practical win.

                                                                                                As far as customizing specific data structure and type combinations, most languages with generics have a way to do that, and I’d bet the Go designers thought of it.

                                                                                                1. 2

                                                                                                  Copy / paste has got it’s own problems, but it lets you avoid a ton of complexity in the toolchain.

                                                                                                  Toolchain development is all about tradeoffs. For instance, I use Typescript; the reference implementation is featureful, but slow to boot, so it keeps a background process alive to cache the heavy lifting, which accumulates state and introduces subtle confusions (eg type errors that don’t exist) until it’s restarted.

                                                                                                  For some problem spaces, the problems introduced by copy/paste pale in comparison to the problems introduced by slow, stateful compilers.

                                                                                                  1. 7

                                                                                                    Copy/paste vs generics is unrelated to compiler bugginess.

                                                                                                    If you carefully pick TypeScript as the comparison point, you can make the case that a buggy toolchain is bad (not that most users care, they just restart the compile process when it starts to go bad).

                                                                                                    But if you were to pick say ReasonML for comparison, you could say that it’s possible to have a solid generics implementation (much less copy-pasting) and a super-fast, accurate compiler.

                                                                                                    I.e. you can have both buggy and non-buggy compilers supporting generics. Hence, unrelated.

                                                                                                    1. 2

                                                                                                      ReasonML is great!

                                                                                                      That said, while the relationship is indirect, it’s there. Adding complexity is never free. It didn’t cost ReasonML speed or reliability, but it costs maintainers time and makes every other feature more difficult to add in an orthogonal way.

                                                                                                      1. 2

                                                                                                        In the scheme of things, is it more important to have a super-simple compiler codebase, or is it more important to put more power and expressiveness in the hands of users? Note that every mainstream language that started without generics, has now added it.

                                                                                                        1. 1

                                                                                                          IMO, there’s such a thing as a right time to do it.

                                                                                                          In the early years it’s more important to keep the simplicity - there aren’t that many users and you’re still figuring out what you want the language to be (not every feature is compatible with every approach to generics).

                                                                                                          Once you’re ready to start generics you need to answer questions like - do you want monomorphisation or lookup tables? Is boxing an acceptable overhead for the improved debugging ergonomics?

                                                                                                          1. 1

                                                                                                            It seems like Go has been going through exactly the process you’re describing.

                                                                                                        2. 2

                                                                                                          I think these comparisons are a bit unfair: isn’t Typescript self hosted, whereas ReasonML is written in OCaml? It seems like Typescript would have a very hard time competing.

                                                                                                          1. 3

                                                                                                            Being able to use lots of existing OCaml bits is a huge advantage.

                                                                                                            Typescript has been able to compete due to the sheer number of contributors - MS pays quite a large team to work on it (and related stuff like the excellent Language Server Protocol, VScode integration).

                                                                                                            However, large teams tend to produce more complex software (IMO due to the added communications overhead - it becomes easier to add a new thing than find out what existing thing solves the same problem).

                                                                                                            1. 1

                                                                                                              I should clarify my comment was more about comparing performance of the two languages.

                                                                                                              OCaml is a well optimized language that targets native machine code so tooling built in OCaml should be more performant than tooling built in Typescript. As a result, it’s hard to compare the complexity of either tool by the performance of the tool. It’s apples and oranges.

                                                                                                            2. 2

                                                                                                              isn’t Typescript self hosted, whereas ReasonML is written in OCaml? It seems like Typescript would have a very hard time competing.

                                                                                                              That’s a strange argument. If it were very hard for them to compete why would they not use OCaml as well, especially since its contemporary alternative, Flow, was written in OCaml too? Or why would they not make TypeScript as good as a language for writing TypeScript in as OCaml is?

                                                                                                              1. 1

                                                                                                                My comment was more about performance, but it wasn’t very clear. It’s hard for Typescript, which is compiled to Javascript and then interpreted/JITed, to create tooling that’s as fast as a language that builds optimized native code.

                                                                                                                Given that Typescript is self hosted it has the advantage that community involvement is more seamless and I don’t want to downplay the power that brings.

                                                                                                          2. 0

                                                                                                            But compilers that support generics are more likely to be buggy. That’s a relation.

                                                                                                            1. 2

                                                                                                              Any source for this rather surprising assertion?

                                                                                                              1. 0

                                                                                                                generics are feature that requires code to implement; code can contain bugs.

                                                                                                                1. 1

                                                                                                                  But a self-hosting compiler with generics is likely to be less verbose (because generics) than one without, so it should be less buggy.

                                                                                                                  1. 1

                                                                                                                    i guess you can’t prove it either way but IME the complexity of algorithms is more likely to cause bugs than verbosity.

                                                                                                          3. 5

                                                                                                            I think Typescript is a straw man. Does this Go implementation of generics slow down the compiler a noticeable amount? There’s nothing inherent to generics that would make compiling them slow.

                                                                                                            On the other hand, copy/pasted code is an ever increasing burden on developer and compile time.

                                                                                                          4. -2

                                                                                                            You are imagining a code base where the same complex data structure is instantiated with two different types. Is that realistic?

                                                                                                            1. 6

                                                                                                              You are imagining a code base where the same complex data structure is instantiated with two different types. Is that realistic?

                                                                                                              Realistic enough that the Linux kernel developers went through the hassle of developing generic associative arrays, circular buffers, and other generic data structures using void*.

                                                                                                              And so did Gnome with GLib, which provides generic lists, hash tables, and trees, along with several others structures, also using void*.

                                                                                                              And the standard libraries of most modern languages include reusable and generic sequence and associative data types, and some times significantly more than that.

                                                                                                              For most data structures, though, focusing on a single code base gives too narrow of a view. Generics allow libraries of data structures to be created, so even though a single code base only use one R* tree (or whatever), that R* tree library can be used as-is by any number of projects.

                                                                                                          5. 8

                                                                                                            The Abstract and Background sections of the draft design doc touch on the motivations. Additionally, each section describing a dimension of the design usually mentions, at least briefly, the motivation for that feature.

                                                                                                            1. 8

                                                                                                              Here is an example that I’ve wanted for ever, and can finally do. Higher order combinators that you can leverage first class functions with!

                                                                                                              Generic map, in go

                                                                                                              1. 1

                                                                                                                That’s the type of thing I have seen as a justification, but I don’t get why that’s so important. Can’t you just use a for loop?

                                                                                                                1. 22

                                                                                                                  “Can’t you just …” goes forever. “Can’t you just write your for loop with labels and jumps in assembly?”^^

                                                                                                                  For me, it’s all about abstraction. Having low level combinators, like this, that I can compose to build higher level abstractions in a generic way is wonderful.

                                                                                                                  ^^: See also whataboutism.

                                                                                                                  1. 3

                                                                                                                    I’m not sure that composing from higher level abstractions is always such a good idea. I like both Go (hobby projects) and Rust (work!) but I still fell that most of the time I prefer this level of abstraction:

                                                                                                                    type Server struct {
                                                                                                                    ...
                                                                                                                        Handler Handler // handler to invoke, http.DefaultServeMux if nil
                                                                                                                    ...
                                                                                                                    }
                                                                                                                    type Handler interface {
                                                                                                                        ServeHTTP(ResponseWriter, *Request)
                                                                                                                    }
                                                                                                                    

                                                                                                                    from this:

                                                                                                                     pub fn serve<S, B>(self, new_service: S) -> Server<I, S, E>
                                                                                                                        where
                                                                                                                            I: Accept,
                                                                                                                            I::Error: Into<Box<dyn StdError + Send + Sync>>,
                                                                                                                            I::Conn: AsyncRead + AsyncWrite + Unpin + Send + 'static,
                                                                                                                            S: MakeServiceRef<I::Conn, Body, ResBody = B>,
                                                                                                                            S::Error: Into<Box<dyn StdError + Send + Sync>>,
                                                                                                                            B: HttpBody + 'static,
                                                                                                                            B::Error: Into<Box<dyn StdError + Send + Sync>>,
                                                                                                                            E: NewSvcExec<I::Conn, S::Future, S::Service, E, NoopWatcher>,
                                                                                                                            E: H2Exec<<S::Service as HttpService<Body>>::Future, B>,
                                                                                                                        {
                                                                                                                        ...
                                                                                                                    

                                                                                                                    Don’t get me wrong, i like type level guarantees and I can see flexibility here, but in my experience with c++, rust and haskell is that generic programming often ends up complicating things to a degree that I personally don’t like.

                                                                                                                    1. 1

                                                                                                                      I think this is going to be a balance that the community has to find. I don’t regularly program in rust, but I’d be quite surprised if it wasn’t possible to get something close to the Go http API in it. The example you pasted seems complicated for the sake of being complicated. In theory, the Go community has been drilled into thinking in terms of the littlest abstraction that’ll work, which maybe makes it possible to generally avoid generic APIs that don’t actually need to be?

                                                                                                                    2. 3

                                                                                                                      “Can’t you just” does not go forever. It is a simpler way to say that the alternative is not significantly harder than what’s proposed. Is there some type of task that would be doable using a generic map but unreasonably hard using for loops?

                                                                                                                      I feel like Go was designed from the ground up to be written in an imperative style, and composing first order functions is more of a functional style of coding. If I understand, without generics you would be nesting for loops rather than composing map functions, which is no more difficult to understand or write.

                                                                                                                      I don’t follow the connection to whataboutism.

                                                                                                                      1. 2

                                                                                                                        I think it’s fine for your style of writing code to be to use loops and conditionals instead of map and filter. I think it’s a fine way to code that makes more sense in an imperative language. Straight for loops and while loops with if statements inside them is just better, more easily understandable code in an imperative language, in my opinion, than .map(...).filter(...).map(...) etc.

                                                                                                                        1. -1

                                                                                                                          Incidentally there is a repo wherein Rob Pike expresses his attitude towards this style of coding:

                                                                                                                          https://github.com/robpike/filter/

                                                                                                                          I wanted to see how hard it was to implement this sort of thing in Go, with as nice an API as I could manage. It wasn’t hard.

                                                                                                                          Having written it a couple of years ago, I haven’t had occasion to use it once. Instead, I just use “for” loops.

                                                                                                                          You shouldn’t use it either.

                                                                                                                          1. 2

                                                                                                                            I mean… that’s like … one man’s opinion… man. See also.

                                                                                                                            Generics are going to create a divide in the Go community, and it’s going to be popcorn worthy. There’s no point of adding Generics to the language if this filter thing “shouldn’t be used,” and the community rejects the abstractions that Generics provide.

                                                                                                                            This divide is easily already seen in the community as it relates to test helpers. On the one hand, there’s a set of developers that say “stdlib testing is more than enough.” On the other hand, there are people who want the full testing facilities of junit, with matchers, lots of assert style helpers, etc. Who is right? They all are, because those things work for their respective teams and projects.

                                                                                                                            This general dogmatic approach to language idioms is why I call it “idiotmatic” Go.

                                                                                                                            1. -1

                                                                                                                              I suppose if Ken and Rob wanted generics they would’ve put them in the original language, and there wouldn’t be this controversy. Time to go back to learning Erlang which seems old and dusty enough to not have big language changes and drama.

                                                                                                                        2. 16

                                                                                                                          You can’t pass a for loop to anything, you can only write it where you need it. Sure, toy examples look like toy examples, but the fact remains that Go has first-class functions, which should be a nice thing, but it doesn’t actually have a type system rich enough to express 90% of the things that make first-class functions worth having.

                                                                                                                          1. -1

                                                                                                                            You can’t pass a for loop to anything, you can only write it where you need it.

                                                                                                                            right, so the example code could be done with a for loop no problem. is there a more motivating example?

                                                                                                                            it doesn’t actually have a type system rich enough to express 90% of the things that make first-class functions worth having.

                                                                                                                            how do you mean?

                                                                                                                          2. 3

                                                                                                                            Consider composing multiple transformations and filters together. With multiple for loops you have to iterate over the array each time, while by composing maps you only need to iterate once.

                                                                                                                            1. 3

                                                                                                                              Just compose the operations inside the loop.

                                                                                                                              for x in y:
                                                                                                                                  ...f(g(x))...
                                                                                                                              
                                                                                                                              1. 2

                                                                                                                                That works in some cases, but it’s pretty easy to find a counter example, too.

                                                                                                                        3. 7

                                                                                                                          In terms of collections, the truth is most of the time a map/slice is a good option. Here’s my top two favorite use cases for generics in go:

                                                                                                                          1. Result<T> and functions that compose over them.
                                                                                                                          2. Typesafe versions of sync.Map, sync.Pool, atomic.Value, even a rust like Mutex
                                                                                                                          1. 5

                                                                                                                            Oh man. I hadn’t even considered a better way to do error handling, eg. a Result type. People are gonna get so mad.

                                                                                                                            1. 5

                                                                                                                              Generics isn’t enough to do what people want to do with error handling 99.99% of the time, which is to return early. For that, you either need a macro, such as the aborted try proposal, or syntactic sugar for chaining such “functions that compose over them” (like Haskell’s do notation).

                                                                                                                              Otherwise you end up with callback hell à la JavaScript, and I think nobody wants that in Go.

                                                                                                                              1. 4

                                                                                                                                I was more thinking of something where the if err pattern is enforced via the type system. You’re still not getting there 100%, you could get reasonably close, with a generic Result type that panics when the wrong thing is accessed, forcing you to check always or risk a panic.

                                                                                                                                r := thing()
                                                                                                                                if r.HasError() { handleError(r.Err()) }
                                                                                                                                else v := r.Val() { handleSuccess(v) }
                                                                                                                                

                                                                                                                                And of course it’s easy to question why this is interesting until you do chaining of things, and get a full on, type safe Result monad.

                                                                                                                                r := thing().andThen(func(i int) { ... }).andThen(func(i int) { ... })
                                                                                                                                if r.IsErr() {
                                                                                                                                   handleErrForWholeComputation(r.Err())
                                                                                                                                } else {
                                                                                                                                   handleSuccessForWholeComputation(r.Val())
                                                                                                                                }
                                                                                                                                

                                                                                                                                The alternative can be seen in things like this where you skirt around the fact that you can’t generically accept a value in one of those called functions. This is also why I said people are going to get so mad. These things are confusing to people who haven’t dealt with them before, and will make Go much more expressive, but less easy to grok without effort.

                                                                                                                          2. 5

                                                                                                                            but is there a real-world setting where this is actually better than just copying code and doing s/type1/type2/g

                                                                                                                            All of them. Copying code manually is one of the worst things you can do in software development. If it weren’t, why even bother writing functions, ever?

                                                                                                                            My sense is that projects that use complex data structures almost always customize the data structures in a way that depends on the data type being stored.

                                                                                                                            The fact that libraries exist that don’t customise in such a way in languages with generics would disprove that notion.

                                                                                                                            1. 6

                                                                                                                              one of the worst things you can do in software development

                                                                                                                              For me that’s “making things unreadable for whoever comes after you”. And sometimes copying a bit of code is the optimal solution for avoid that.

                                                                                                                              1. 0

                                                                                                                                but is there a real-world setting where this is actually better than just copying code and doing s/type1/type2/g

                                                                                                                                All of them. Copying code manually is one of the worst things you can do in software development. If it weren’t, why even bother writing functions, ever?

                                                                                                                                I disagree with your implication that the use of functions means code should never be copied. For example if you want to use strlcpy() in a portable C program, it makes more sense to put a copy in your source tree rather than relying on an external library. An extra dependency would add more headache than just copying the code.

                                                                                                                                My sense is that projects that use complex data structures almost always customize the data structures in a way that depends on the data type being stored.

                                                                                                                                The fact that libraries exist that don’t customise in such a way in languages with generics would disprove that notion.

                                                                                                                                That’s why I said “almost always.” And remember that the existence of a library doesn’t mean it is used with any frequency.

                                                                                                                              2. 3

                                                                                                                                Suppose you have a structure parametrizable by types T1, T2. You’re writing it in Go, so you assume that it’s ok if T1=string, T2=int. Also, in some of the places, you were using int for purpose unrelated to T2 (ie. if T2=foo, then there are still ints left in the source). Another programmer wants to copy-paste the code and change some types. How does he do it?

                                                                                                                                1. 2

                                                                                                                                  I think “this would make copy-pasting code harder” is not so compelling an argument. One of the major points of introducing generics is that it would eliminate much of the present need for copy/paste in Go.

                                                                                                                                  1. 2

                                                                                                                                    Yes it would be harder than a search-and-replace, but that is still abstract and unrelated to any real-world use case.

                                                                                                                                    Yes, I’m just counterpointing the parent commenter’s argument. I know the value of generic structures.

                                                                                                                                  2. -1

                                                                                                                                    Yes it would be harder than a search-and-replace, but that is still abstract and unrelated to any real-world use case.

                                                                                                                                1. 1

                                                                                                                                  My best guess about why OAuth took off while client certificates did not is that one can implement the client side of the former in JavaScript and run it in a browser, but probably not the latter.

                                                                                                                                  1. 6

                                                                                                                                    Every client implementation of OAuth which has no server-side component is leaking their secret key, which is a Bad Thing you are Not Supposed To Do.

                                                                                                                                    1. 3

                                                                                                                                      With OAuth2, app secret keys should not exist for public clients (no matter if web or native, keys can be extracted either way).

                                                                                                                                      The old way of implementing public clients was implicit grant; now it’s PKCE (RFC 7636).

                                                                                                                                      1. 2

                                                                                                                                        I think it’s important to point out that this was a limitation of OAuth, but not a limitation of OAuth2, which is what most implementations use these days. I am assuming @jimdigriz is assuming OAuth2, and you OAuth 1.0. Are my assumptions correct?

                                                                                                                                        *Edit—I am wrong here. I forgot that there’s a client secret possible for some OAuth2 flows as well.

                                                                                                                                        1. -1

                                                                                                                                          Not all client implementations do https://gitlab.com/jimdigriz/oauth2-worker

                                                                                                                                          1. 10

                                                                                                                                            This is a placebo of the worst order, a “security” library which is nothing of the sort. This will still leak your client secrets, it is logically impossible not to if you’re completing the OAuth flow from the client side.

                                                                                                                                            1. -1

                                                                                                                                              So instead of walking through the methodology in there, you just decided to make wild statements.

                                                                                                                                              Marvelous.

                                                                                                                                              1. 9

                                                                                                                                                I did read it, and I understand what it’s trying to do, and what it’s not doing is keeping your client secret a secret. It’s keeping it from other JavaScript, but anyone on your page can find the secret by popping up the network panel and watching the request go out. Try it yourself.

                                                                                                                                                This library should come with a big bold header telling you that it does absolutely nothing at all to keep your client secret safe from an adversary who knows where the “view source” button is, and that it would be impossible to do so effectively.

                                                                                                                                                Client side security, isn’t. This is a cold, hard fact.

                                                                                                                                                1. -2

                                                                                                                                                  Pray, do tell, what server side componment would fix this attack vector?

                                                                                                                                                  1. 11

                                                                                                                                                    If you put it on the server, then you don’t have to send it to the client! The whole point of the secret token is that you keep it on your server, behind your firewall, and then issue the request to obtain the exchange token there. NOT in code that you’ve sent to the client to do whatever they want with.

                                                                                                                                                    CLIENT SIDE CODE IS NOT SECURE.

                                                                                                                                                    1. 1

                                                                                                                                                      What does the client use to authenticate its-self? What is it that the client communicate to authenticate its-self. Your statement of ‘put the token on the server’ is nonsensical as the problem is authenticating a user-agent.

                                                                                                                                                      No one gives a damn what an untrusted client does with a token, it is authorised for whatever its allowed to do, no more, no less.

                                                                                                                                                      You also seem to be trying to add substance to your argument by making out this secret works like a root credential, which is an implementation detail and irrelevant.

                                                                                                                                                      Your arguments read as if you need to swot up on you AAA.

                                                                                                                                                      1. 8

                                                                                                                                                        I don’t follow your line of questioning, but from the linked repo.

                                                                                                                                                        client_secret [optional and not recommended]: your application secret

                                                                                                                                                        SAP’s are considered a public (‘untrusted’) client as the secret would have to published making it no longer a secret and pointless

                                                                                                                                                        This is what you risk losing, not the access token. The application secret has to be stored somewhere and if there is no server-side component then its on the client, which like the documentation says is insecure.

                                                                                                                                                        1. 4

                                                                                                                                                          No one gives a damn what an untrusted client does with a token, it is authorised for whatever its allowed to do, no more, no less.

                                                                                                                                                          Do I understand correctly that you actually don’t care that an untrusted client has access (even limited) without you knowing it?

                                                                                                                                                          Why do you need oauth2 then?

                                                                                                                                          2. 2

                                                                                                                                            Over in the 802.1X world, EAP-TLS (client certificates) is mostly a pain not at initial provisioning, but renewal of the certificates and the UX around that. Though a mostly awful standard, EAP-FAST tried to address this (including provisioning) and now things like TEAP are coming out the woodwork.

                                                                                                                                            1. 1

                                                                                                                                              EAP-TLS of course is fixed by having irresponsibly long validity times on the certificates, in the hopes that the user tosses the device before the certificate expires.. And then you hope your user comes to you for getting a new certificate instead of reusing the one for their old device..

                                                                                                                                          1. 27

                                                                                                                                            It’s nice to read a review that feels honest and isn’t spewing bile and hatred about every little thing. This one is recommended.

                                                                                                                                            I concur with assertion that the trackpad is too large, although I use a 2017 MBPro so I avoid typing on it as much as possible.

                                                                                                                                            1. 2

                                                                                                                                              I concur with assertion that the trackpad is too large, although I use a 2017 MBPro so I avoid typing on it as much as possible.

                                                                                                                                              I have a 2018 Macbook Pro. Yes its getting into the crazy size territory.

                                                                                                                                              1. 2

                                                                                                                                                It’s nice to read a review that feels honest and isn’t spewing bile and hatred about every little thing.

                                                                                                                                                Indeed, this was a very nice, balanced, review.

                                                                                                                                                I concur with assertion that the trackpad is too large, although I use a 2017 MBPro so I avoid typing on it as much as possible.

                                                                                                                                                I feel like they should offer something that combines the Air and the Pro.

                                                                                                                                                The Air 2020 has a smaller trackpad, no Touch Bar (which is a feature), and a 10th generation Ice Lake CPU. The primary thing that people may dislike is its weaker CPU, which is designed for low TDPs. Another downside is just 2 USB-C ports.

                                                                                                                                                The two baseline MacBook Pro 13” 2020 models are a travesty. They are basically the low-end 2018/2019 model with the new Magic Keyboard (good) and Touch Bar (bad). The CPU is still slower than my previous Touch Bar MacBook Pro 2018 and they only have 2 ports. These models basically combine the downsides of the Air (weaker CPU, 2 USB-C ports) and the Pro (Touch Bar). To add to the offense, you get an 8th generation Intel chip with much lower memory bandwidth and slower GPU than the 2020 Air.

                                                                                                                                                The high-end MacBook Pro 13” 2020 are pretty good with 10th gen CPUs and 4 USB-C ports. Unfortunately, it has a Touch bar (+ larger trackpad if you do not like it).

                                                                                                                                                What seems to be missing for most folks is basically the MacBook Air (perhaps in a slightly thicker enclosure) that has a higher TDP CPU like the Pros.

                                                                                                                                                That said, I never had problems with accidental touch inputs with the Pro 2018 or Air 2020.

                                                                                                                                                1. 3

                                                                                                                                                  The two baseline MacBook Pro 13” 2020 models are a travesty. They are basically the low-end 2018/2019 model with the new Magic Keyboard (good) and Touch Bar (bad). The CPU is still slower than my previous Touch Bar MacBook Pro 2018 and they only have 2 ports

                                                                                                                                                  My theory is that they have positioned this model (and purposefully not updated/hobbled it a bit) for a move to Arm in the future. It will allow for a nice markety-type reveal such as “we made an Arm laptop that is faster than the previous intel model! woo!”.

                                                                                                                                                  1. 3

                                                                                                                                                    That’s actually quite smart. “Up to 20x faster!”

                                                                                                                                                2. 1

                                                                                                                                                  I also have a 2017 MBP and I’ve gotten used to changing my palm resting position to be on either side of the track pad. Most of the time, however, I use a regular keyboard and mouse plugged into a usbc hub. The most obnoxious feature I’d remark on is Siri on the upper right corner - 9/10 times I wanted to hit delete or = and instead got that silly app.

                                                                                                                                                  1. 2

                                                                                                                                                    You can customize the touch bar in system preferences. I have mine to only display the volume, brightness and media keys.

                                                                                                                                                1. 13

                                                                                                                                                  I read it but there is something I am still missing.

                                                                                                                                                  So say I have 10,000 notes. I write a new one. How on earth could I link it with others that I’ve forgotten about? Surely I cannot re-read all of 10,000 to see which ones I should link together. I do not get this part of it.

                                                                                                                                                  1. 11

                                                                                                                                                    Incidently, I just stumbled upon this Zettelkasten-like note: Notes should surprise you:

                                                                                                                                                    If reading and writing notes doesn’t lead to surprises, what’s the point?

                                                                                                                                                    If we just wanted to remember things, we have spaced repetition for that. If we just wanted to understand a particular idea thoroughly in some local context, we wouldn’t bother maintaining a system of notes over time.

                                                                                                                                                    This is why we have dense networks of links (Evergreen notes should be densely linked): so that searches help us see unexpected connections.

                                                                                                                                                    This is why we take Evergreen notes should be concept-oriented: so that when writing about an idea that seems new, we stumble onto what we’ve already written about it (perhaps unexpectedly).

                                                                                                                                                    The linked note inside starts with this:

                                                                                                                                                    It’s best to factor Evergreen notes by concept (rather than by author, book, event, project, topic, etc). This way, you discover connections across books and domains as you update and link to the note over time (Evergreen notes should be densely linked).

                                                                                                                                                    So one aspect of the answer suggested here: By writing notes about general concepts, you provoke revisiting them. Through heavy linking you now create connections between related ideas. Through further maintenance like overview notes transitive connections become more direct connections and thus closer. (As a self-refential example: This reminds me of union-find and how it merges disjoint sets).

                                                                                                                                                    1. 5

                                                                                                                                                      How does one find “related notes”?

                                                                                                                                                      I believe the answer lies here:

                                                                                                                                                      Luhmann described his Zettelkasten in different ways. Sometimes he called it a conversation partner and sometimes he described it as a second memory, cybernetic system, a ruminant, or septic tank.

                                                                                                                                                      You actually just keep a big chunk of the notes in your memory. You don’t memorize their literal content, but you know of their existence, so you know approximately where to look. I would say that the Zettelkasten was a tool to enhance his own memory rather than a tool to do the remembering for him.

                                                                                                                                                      The secret to keeping the existence of the largest part of 90.000 notes in memory is probably revisiting them regularly, by following links and browsing at random, both of which the Zettelkasten invites you to do. Luhmann’s notes were all centered around his single general focus area: philosophy and social science, so he was thinking about the full body of work all the time.

                                                                                                                                                      I think the brain is better at this sort of thing than we generally acknowledge. I actually believe that this may be an argument for using an analogue Zettelkasten. You come up with an idea and your brain hints that you have thought about something related before, you just don’t know when and what exactly. You might vaguely remember a particularity of a card though, maybe a tear, a stain or even the smell. So you go browsing, and soon enough you run into a connected idea, which leads you to the subweb of existing ideas that are relevant to the new idea. This rummaging around has the additional benefit of refreshing your memory of existing notes.

                                                                                                                                                      The efficiency on such a large scale is probably for a large part determined by your ability to leverage the hints your unconsciousness gives you, which I think is why Luhmann describes his Zettelkasten in varying, not very rational or strict ways, in an effort to capture this unconscious process.

                                                                                                                                                      1. 4

                                                                                                                                                        My interpretation is that you would have meta-notes that serve as an index for notes about a given topic. (I do that and it’s very useful) So you might not remember the existing 10,000 notes, but surely you can relate your new note to some topics you already touched, and then you can go look at the index for those, and follow the links that look relevant.

                                                                                                                                                        Then, I guess one assumption is that, while exploring the existing web of notes to connect it to your new note, one should dedicate a bit of time and make some new connections if they feel relevant, i.e. do some general “maintenance” of the system.

                                                                                                                                                        1. 2

                                                                                                                                                          If you completely forgot about something, then you have no trigger to even look for something to link to. However, if you have a vague memory of something, a system of indices can be helpful to refresh your memories.

                                                                                                                                                        2. 3

                                                                                                                                                          It’s about destruction and creation. You deconstruct something to use it’s parts for creating something new.

                                                                                                                                                          1. 2

                                                                                                                                                            This is exactly the question none of my reading has answered. I haven’t read “Taking Notes the Smart Way”, but I’ve otherwise read a lot, and nothing seems to address that question.

                                                                                                                                                            I have my own ideas, but I’d love to see how other people solve this.

                                                                                                                                                            1. 7

                                                                                                                                                              Yeah I’m starting to think that “do X the smart way” is mostly BS for most values of X.

                                                                                                                                                              The more I go on the more it seems to me that the system is not important as long as you’re consistent with its use (whether it’s note taking or organising or anything else).

                                                                                                                                                              Also, the most productive people I’ve seen… They don’t use fancy things that make them “super productive”. They just sit down and do the work, and they got good and fast at it by means of practice.

                                                                                                                                                              The more I go on with life the stronger I feel the smell of BS.

                                                                                                                                                              1. 4

                                                                                                                                                                I gave it some thought and this is what I have:

                                                                                                                                                                Linking problem is not solved. If it was solved there would not be any need for adding links in the first place. Why add links at all if you can easily find other notes related to the current one? So the fact that links exist leads me to the conclusion that linking is the actual hard part of this method.

                                                                                                                                                                Second - the whole approach is a hyperlink data base structure before data bases became a thing. This system can be implemented in a single table having 3 columns: 1) ID, 2) Note, 3) References. We have software now so maintaining a data-base in a furniture is probably obsolete.

                                                                                                                                                                But most importantly, like the article said, Zettelkasten  becomes better the more notes are added to it. OK. So the logical conclusion is to invite other people to add their notes to it. Then it grows faster. Everyone is adding their ideas, and creating links between ideas. To me it seems such a state is the ultimate goal of this system. But we have this now, it’s called the internet.

                                                                                                                                                                So I think whatever made that one german scholar so productive probably wasn’t the system itself.

                                                                                                                                                                1. 1

                                                                                                                                                                  You say that as if the internet isn’t a hugely transformative, productivity increasing tool.

                                                                                                                                                                  1. 1

                                                                                                                                                                    I would go as far as to say that for many people it’s the opposite. It can be used as productivity increasing tool and an amazing one at that. But many people use it for other things completely.

                                                                                                                                                                2. 1

                                                                                                                                                                  I think the theory is that if you’re taking a note, you’ve probably already got a bunch of notes about the thing you’re researching handy, so you link to those. For my part that doesn’t match how I generally take notes (I often find myself making note of something I stumble on, and writing summaries/self-tutorials of stuff I’m studying to ‘learn it’ more thoroughly).

                                                                                                                                                                  That said, the Zettelkasten core idea seems to me to be ‘smaller notes, more often’, and also to follow the old adage: “Graphs are a set of Edges that incidentally have some Vertices attached.” Links and granularity are the key takeaways, and there are good ways to do that that aren’t exactly Zettelkasten.

                                                                                                                                                                  1. 1

                                                                                                                                                                    I’m currently trying TiddlyWiki because its UI encourages smaller notes.

                                                                                                                                                                    With a physical Zettelkasten you implicit see neighbor slips as you search a linked one. This is lost in a digital version where searching is delegated to computer and effectively instant. It would be easy to track all kind of implicit connections (backlinks, created before and after) but how to present that in a helpful way?

                                                                                                                                                                3. 2

                                                                                                                                                                  I don’t think the system is supposed to answer that question. Connecting ideas is the job of the human, not the system. However, if you do connect some ideas, you don’t have to remember that connection. Your web of thinking is externalized.

                                                                                                                                                                  I’m sure there are strategies. Randomly showing any two cards seems as good as any strategy. This would only increase the probability (marginally) that two ideas get connected. It would still be up to you to figure out how they are connected.

                                                                                                                                                                  1. 4

                                                                                                                                                                    But to create the connection you have to know that the connection is possible, so you have to be aware of the other cards to which you can connect this one. That’s the essence of what a zettelkasten is supposed to be, and what no one is explaining.

                                                                                                                                                                    Here, I’ve read something, I’ve written a short, pithy note. Where do I file it? To what other cards is it connected? How do I find them?

                                                                                                                                                                    I have some ideas, but it’s supposed to be a solved problem via this method, and I’m seeing zero discussion of it in any of my reading.

                                                                                                                                                                    There’s the puzzle.

                                                                                                                                                                    1. 4

                                                                                                                                                                      I think of zettelkasten a bit differently. In database terminology, I see it as normal form applied to ideas. Ideas are often tightly coupled to their original context. This is why it’s natural to apply a hierarchical structure to notes. You just place the note under a folder which represents the original context. In zettelkasten you make the idea atomic and if you want to give it context then you have to reify that context with a link (a foreign key). Zettelkasten isn’t your schema, zettelkasten is relational algebra. You’re free to come up with any schema you want.

                                                                                                                                                                      Where do I file it?

                                                                                                                                                                      In the same folder with everything else. It’s flat. The structure is provided by the links.

                                                                                                                                                                      How do I find them?

                                                                                                                                                                      I use org-roam in emacs. A digital system helps with search. The original zettelkasten had physical organization by topic and you could traverse the links from there. I’ve only been doing this for a few weeks so maybe search might not scale.

                                                                                                                                                                      Btw, I think your questions are great ones. All I’m saying is I don’t think the system has an answer.

                                                                                                                                                                      1. 2

                                                                                                                                                                        Thanks for the reply … I pick up on this:

                                                                                                                                                                        How do I find them?

                                                                                                                                                                        I use org-roam in emacs. A digital system helps with search.

                                                                                                                                                                        I agree that search solves/avoids a lot of the problems that a purely analog system would/did have.

                                                                                                                                                                        But the whole point of a zettelkasten is that it helps with the search, either to avoid it, or to guide it, or to augment it. Luhmann described “having a conversation” with his zettelkasten.

                                                                                                                                                                        So I’m here, I have a new “card” … I can search the existing ZK for cards that have the same words, but that suffers the problem of combinatorial explosion, and it’s not using the zettelkasten in any kind of clever way.

                                                                                                                                                                        I think there are answers to be found, and perhaps Luhmann had some, and even his enthusiasts don’t really “get it” beyond having a huge box of index cards with some sort of indexing system. It feels from my reading that Luhmann had more than that. Otherwise it’s just a wiki with search.

                                                                                                                                                                        As you may be able to tell, I’ve thought about this a lot.

                                                                                                                                                                        1. 1

                                                                                                                                                                          I think the idea is to never make a note without linking to it from some context of an existing note. So you might have a note on when is the best time to do exercise. That note should be referenced from an index card on exercise, or maybe a note on daily routines.

                                                                                                                                                                          I think there is some hope it’ll be like a wiki, but maybe something more like tvtropes or c2 than Wikipedia where all the ideas are enmeshed are easy to move between.

                                                                                                                                                                      2. 3

                                                                                                                                                                        You connect nodes you know of. Since nodes are connected to nodes, this lets you wander the node links. No node contains every link, because that’s not their job. Their job is to link to whatever you still remember so you can later link it to what you’ve long forgotten.

                                                                                                                                                                        1. 2

                                                                                                                                                                          I have some ideas, but it’s supposed to be a solved problem via this method, and I’m seeing zero discussion of it in any of my reading.

                                                                                                                                                                          How to Take Smart Notes is worth a read, IMO, though it is still kind of nebulous on some points.

                                                                                                                                                                          There’s an “Everything You Need to Do” section. It says:

                                                                                                                                                                          Now add your new permanent notes to the slip-box by:

                                                                                                                                                                          a) Filing each one behind one or more related notes (with a program, you can put one note “behind” multiple notes; if you use pen and paper like Luhmann, you have to decide where it fits best and add manual links to the other notes). Look to which note the new one directly relates or, if it does not relate directly to any other note yet, just file it behind the last one.

                                                                                                                                                                          b) Adding links to related notes

                                                                                                                                                                          c) Making sure you will be able to find this note later by either linking to it from your index or by making a link to it on a note that you use as an entry point to a discussion or topic and is itself linked to the index.

                                                                                                                                                                          Presumably, in order to find things to link if you don’t have them ready to hand, you use the existing index.

                                                                                                                                                                          1. 1

                                                                                                                                                                            The magic seems to lie here:

                                                                                                                                                                            a) Filing each one behind one or more related notes … b) Adding links to related notes

                                                                                                                                                                            This is the question no material or article seems to be answering: How does one find “related notes”? It refers to “the index”, but that’s rarely referred to elsewhere and seems utterly mysterious. How are things indexed?

                                                                                                                                                                            I should write up my musings as best I can to further reveal my confusion and incomprehension. I’ll try to do that.

                                                                                                                                                                            1. 1

                                                                                                                                                                              So, full disclosure, I’ve taken notes on cards before, but at the time I gave them either meaningful names or datestamps rather than Luhmann-style sequential identifiers or what-have-you, so I just kept them in a card box sorted by alpha / date. The collection never grew substantial enough for me to think about other forms of indexing. The cards I’ve held onto are in a single cardboard file box with little alphabet dividers I bought at an office supply store.

                                                                                                                                                                              That said, indexes for paper information storage are a pretty well-established technology.

                                                                                                                                                                              If I were going to take a crack at it for a paper Zettelkasten, I would:

                                                                                                                                                                              • Set up a large card box with alphabet dividers.
                                                                                                                                                                              • When adding a note to my permanent collection:
                                                                                                                                                                                • Search the index for keywords pertaining to the new note
                                                                                                                                                                                • If no card exists in the index for the keyword (name, phrase, concept, etc.) I want to be able to track down again:
                                                                                                                                                                                  • Print the keyword on top of a fresh card
                                                                                                                                                                                • Write down the ID of the related note on any relevant cards (either existing ones or the ones I’ve just created)
                                                                                                                                                                                • File the cards with keywords alphabetically in my index

                                                                                                                                                                              Here’s an abbreviated example from a random page of the index in the first reference volume I could find on my office bookshelf, The Chicago Manual of Style:

                                                                                                                                                                              …
                                                                                                                                                                              ornaments for text break, 1.56 
                                                                                                                                                                              orphans (lines), 2.113, p.899
                                                                                                                                                                              o.s. (old series), 14.132
                                                                                                                                                                              outlines
                                                                                                                                                                                  basic principles, 6.121
                                                                                                                                                                                  parts of a book, 1.4
                                                                                                                                                                                  publishing process, 2.2, fig. 2.1, fig. 2.2
                                                                                                                                                                                  punctuation and format, 6.94, 6.126
                                                                                                                                                                                  See also: lists
                                                                                                                                                                              Oxford comma, 6.18-21. See also commas.
                                                                                                                                                                              …
                                                                                                                                                                              

                                                                                                                                                                              This is a ~900 page reference work with fairly dense text, and about a hundred pages of index, so that ought to give you some very rough idea what ratio is useful for a working reference system, and how far an alphabetized index can scale. The references are mostly to section numbers or figures rather than pages, which seems like a pretty useful parallel to how things could work with numbered cards.

                                                                                                                                                                              The other thing you might want to research is library card catalog approaches. The paper card catalog systems I was taught at length in elementary school have all pretty well been obliterated by electronic databases by now, but there was once a range of well-developed techniques there for indexing into very large collections by author and subject matter.

                                                                                                                                                                              There’s nothing to stop anyone from translating these techniques directly to software, though there are probably more automated ways to get most of the same benefits in any given system. (i.e., tagging systems, automatic keyword indexing, and good old grep.)

                                                                                                                                                                      3. 1

                                                                                                                                                                        I’m thinking of trying this out and my idea was to try some sort of transitive closure view and “show me five random notes” thingymajiggy.

                                                                                                                                                                        1. 1

                                                                                                                                                                          How on earth could I link it with others that I’ve forgotten about? Surely I cannot re-read all of 10,000 to see which ones I should link together. I do not get this part of it.

                                                                                                                                                                          Practically speaking:

                                                                                                                                                                          • in a paper system, the answer is probably an index and a sorted reference collection
                                                                                                                                                                          • in an electronic system, the answer is some combination of search and tagging

                                                                                                                                                                          Relatedly, the cards (or other unit of note-taking) aren’t intended to be an append-only log. You’re supposed to interact with the system and refine the web of connections as you go, so it may not matter if something is initially orphaned.

                                                                                                                                                                        1. 26

                                                                                                                                                                          inheritance is something that makes your code hard to understand. Unlike function, which you can read just line by line, code with inheritance can play “go see another file” golf with you for a long time.

                                                                                                                                                                          This isn’t an argument against inheritance, it’s an argument against modularity: Any time you move code out of inline you have the exact same “problem” (to the extent it is a problem) and you can only solve it the same way, with improved tooling of one form or another. ctags, for example, or etags in Emacs.

                                                                                                                                                                          1. 31

                                                                                                                                                                            Inheritance has this problem to a much larger degree because of class hierarchies. Tracing a method call on a class at the bottom of the tree, requires checking every parent class to see if its overridden anywhere. Plain function calls don’t have that problem. Theres only a single definition.

                                                                                                                                                                            1. 7

                                                                                                                                                                              Plain function calls don’t have that problem. Theres only a single definition.

                                                                                                                                                                              Unless we start using higher order functions when the function is passed around as a value. Such abstraction creates the exact same problem, only now it’s called “where does this value originate from”.

                                                                                                                                                                              1. 5

                                                                                                                                                                                Yes, which is why higher order functions are another tool best used sparingly. The best code is the most boring code. The most debuggable code is the code that has the fewest extension points to track down.

                                                                                                                                                                                This is, of course, something to balance against debugging complicated algorithms once and reusing them, but it feels like the pendulum has swung too far in the direction of unwise extensibility.

                                                                                                                                                                                1. 4

                                                                                                                                                                                  For extra fun, use higher-order functions with class hierarchies!

                                                                                                                                                                                2. 4

                                                                                                                                                                                  The best is python code where the parent class can refer to attributes only created in child classes. There are equivalents, but less confusing, in languages like Java.

                                                                                                                                                                                  1. 1

                                                                                                                                                                                    Isn’t the example in the linked article doing exactly that?

                                                                                                                                                                                    1. 2

                                                                                                                                                                                      Okaaaay… what’s self.connect doing? Ah, it raises NotImplementedError. Makes sense, back to SAEngine:

                                                                                                                                                                                      Not exactly. :)

                                                                                                                                                                                      1. 1

                                                                                                                                                                                        Check out Lib/_pyio.py (the Python io implementation) in CPython for lots of this.

                                                                                                                                                                                    2. 1

                                                                                                                                                                                      The overrides is mostly for modularity and reduce code duplication. Without classes, you might either end up with functions with tons of duplicated code, or tons of functions having a call path to simulate the “class hierarchies”. And yes, it’s going to make the code harder to read in some cases, but it also makes the code much shorter to read.

                                                                                                                                                                                      1. 6

                                                                                                                                                                                        Without classes, you might either end up with functions with tons of duplicated code

                                                                                                                                                                                        Why? There is literally no difference in code re-using between loading code through inheritance vs function calls, apart from possibly needing to pass a state to a function, that could otherwise be held in class instances (aka objects). this is certainly less than class definition boilerplates.

                                                                                                                                                                                        or tons of functions having a call path to simulate the “class hierarchies”

                                                                                                                                                                                        The call chain is there in both cases. It’s just that in the class-based approach it is hidden and quickly becomes a nightmare to follow. Each time you call a method statically or access a class atribute, you are basically pointing to a point in your code that could be hooked to different points in the hierarchy. This is a problem. People don’t think it is a big deal when they write a simple class and know it well, because the complexity is sneaky. Add another class and all of the sudden you brought in a whole other hierarchy into the picture. Each time you read “this” or “instance.something”, you’re up for am hunt. And each other hierarchy you bring into the picture increases complexity geometrically. Before you know, the project is unmanageable, the ones writing it went on to some green field project, doing a similar mess again for some poor soul to struggle with after them.

                                                                                                                                                                                        And yes, it’s going to make the code harder to read in some cases, but it also makes the code much shorter to read

                                                                                                                                                                                        It doesn’t really. People fall for this because you can instantiate a class and get a bunch of hidden references that are all available to you at will without you need to explicitly pass them to each method, but you only get this through defining a class, which is way more verbose than just passing the references you need.

                                                                                                                                                                                        All that said, what classes do offer in most languages is a scope that allows for fine grain control of data lifecycle. If we remove inheritance, then class members are akin to use global variables in non-OOP languages. But you can create as many scopes as you want. I which languages like python would do this as, for the same reason as OP, I suffer from working with OOP codebases.

                                                                                                                                                                                        1. 4

                                                                                                                                                                                          You make it sound like inheritance is the only way to reduce code duplication. In my experience that is simply not true, you can always use composition instead. E.g. Haskell doesn’t support inheritance or subtyping and you still get very compact programs without code duplication.

                                                                                                                                                                                          1. 5

                                                                                                                                                                                            Without classes, you might either end up with functions with tons of duplicated code, or tons of functions having a call path to simulate the “class hierarchies”

                                                                                                                                                                                            This is only true in my experience if you’re trying a functional approach with an OO mindset. There are other ways to solve problems, and many of them are far more elegant in languages designed with functional programming as the primary goal.

                                                                                                                                                                                        2. 5

                                                                                                                                                                                          When you move a bit of code out of your file it’s not going to call back function from the first file. You going to even make sure this is the case, that there is no circular dependency, because it makes (in cases when a language allows to make you one) code harder to read. In case of inheritance, those games with calling everything around is just normal state of things.

                                                                                                                                                                                          Of course, example in the article is small and limited, because pulling a monster from somewhere is not going to make it more approachable, but surely you’ve seen this stuff in the wild.

                                                                                                                                                                                          1. 4

                                                                                                                                                                                            You might do that, in the same way that you might carefully document your invariants in a class that allows inheritance, mark methods private/final as needed, etc. But you also might not do that. It sounds a bit as if you’re comparing well-written code without inheritance to poorly written code with it.

                                                                                                                                                                                            Not that there isn’t lots of terrible inheritance based code. And I’d even say inheritance, on balance, makes code harder to reason about. However, I think that the overwhelming issue is your ability to find good abstractions or ways of dividing up functionality–the choice of inheritance vs. composition is secondary.

                                                                                                                                                                                            1. 2

                                                                                                                                                                                              It’s just that without inheritance it’s easier to make good abstractions. Inheritance affords you to do wrong thing easily, without any friction - just read a good article about that few weeks ago.

                                                                                                                                                                                          2. 4

                                                                                                                                                                                            Interesting article from Carmack about inlining everything:

                                                                                                                                                                                            http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inlined-code.html

                                                                                                                                                                                            1. 4

                                                                                                                                                                                              This isn’t an argument against inheritance, it’s an argument against modularity: Any time you move code out of inline you have the exact same “problem” (to the extent it is a problem) and you can only solve it the same way, with improved tooling of one form or another. ctags, for example, or etags in Emacs.

                                                                                                                                                                                              Not really, including code via accessing a class or object member forces you to manually go figure out which implementation is used, or where the implementation in a web of nested namespaces. In the case of function, each symbol is non-ambiguous. This is a big deal. If you have types A and B, with A having an attribute of the type B, each of these types containing a 3 level hierarchy, and you call A.b.some_b_method(). That could be defined in 9 different places, and if it is, you need to figure out which that symbol resolves to. This is a real problem.

                                                                                                                                                                                              1. 2

                                                                                                                                                                                                This isn’t an argument against inheritance, it’s an argument against modularity:

                                                                                                                                                                                                Yeah, all code should be in a single file anyway. No more chasing of method definitions across multiple files. You just open the file and it’s all there…

                                                                                                                                                                                                1. 2

                                                                                                                                                                                                  Any form of modularity should be there to raise the level of abstraction. ie. Become a building block, that is solid (pun intended) firm and utterly reliable, that you can use to understand the higher layers.

                                                                                                                                                                                                  You can peer inside the building block if you need to, but all you need to understand about it, to understand the next level up, is what it does, not how it does it.

                                                                                                                                                                                                  Inheritance is there to allow you to know that “all these things IS A that”. ie. I can think of them and treat all of them exactly as I would treat the parent class. (ie. The L in SOLID)

                                                                                                                                                                                                  I can utterly rely on the fact that the class invariant for the superclass holds for all subclasses. ie. The subclasses may guarantee other things, but amongst the things they guarantee, is that the super class’s class invariant holds.

                                                                                                                                                                                                  I usually write a class invariant check for every class I write.

                                                                                                                                                                                                  I then invoke it at the end of the constructor, and the beginning of the destructor, and at the start and end of every public method.

                                                                                                                                                                                                  As I become more convinced of the correctness of what I’m doing, I may remove some for efficiency reasons. As I become more paranoid, I will add some.

                                                                                                                                                                                                  In subclasses, the class invariant check always invokes the parent classes invariant check!

                                                                                                                                                                                                1. 6

                                                                                                                                                                                                  what’s up with the first sentence in this article? really not a good way to start off a post

                                                                                                                                                                                                  1. 12

                                                                                                                                                                                                    How so? Honest question. Riot is wholly owned by Tencent, so it’s not inaccurate. It’s similar to the Huawei / 5G situation, in my view.

                                                                                                                                                                                                    1. 12

                                                                                                                                                                                                      Riot’s engineering is headquartered in Los Angeles.

                                                                                                                                                                                                      Allegations made against Riot prior to being bought by Tencent include bro culture, glass ceilings, and sexual harrassment. In addition, I’ve heard anecdotes that they routinely ask design interviewees to show them ideas for chamipions, which are then gently copied into the game, regardless of whether the interviewee gets the job.

                                                                                                                                                                                                      Riot already did not sound like a good kernel-driver vendor, regardless of whether any particular governments have undue influence over them.

                                                                                                                                                                                                      1. 6

                                                                                                                                                                                                        I spent a very short time working from their office as a contractor to another company that had a project with them.

                                                                                                                                                                                                        It’s hard to quite explain it - particularly as I’m not American, and it was only my second time in the country - but the whole time we were there, the place seemed.. weird.

                                                                                                                                                                                                        1. 3

                                                                                                                                                                                                          Please elaborate

                                                                                                                                                                                                          1. 3

                                                                                                                                                                                                            As I said, some of what experienced could be cultural.

                                                                                                                                                                                                            The mentality seemed a bit like you sometimes see in futuristic movies where “corporations” are the new nation states, and people are loyal to a company, even more than most would currently be loyal to a country.

                                                                                                                                                                                                            The company itself had expectations of all employees playing their game for a significant amount of time on a daily basis. There’s eating your own dog food, and then there’s force-feeding your dog food to your staff through a tube. Our work was related to a web-rendered “store” - no more related to gameplay than an online shopping site for groceries is related to cooking - but they still insisted we all play their game at least once while there.

                                                                                                                                                                                                            The experience left me with the feeling that they’re convinced of their own self-importance, and can’t fathom how a computer game is less interesting than washing dishes to some people.

                                                                                                                                                                                                      2. 2

                                                                                                                                                                                                        then why doesn’t it say “would you allow a tencent application [etc etc]”? it’s not inaccurate, but saying it’s accurate is even more of a stretch, and the regardless of what the author intended, it only furthers the image of china that’s also used for yellow peril rhetoric

                                                                                                                                                                                                        1. 2

                                                                                                                                                                                                          It’s similar to how Donald Trump called coronavirus the “Chinese virus”. Its complete accurate the pandemic started in China but to call it in that manner feels like a dog whistle for other racial prejudices. ie. that Chinese people are foreign or anti-freedom. I get the impression that the author tried to find the adjective that would have the most impact, and that Chinese was the scariest word they come up with.

                                                                                                                                                                                                        2. 6

                                                                                                                                                                                                          Yet it is quite appropriate.

                                                                                                                                                                                                          Would you? I wouldn’t. Hell no.

                                                                                                                                                                                                          1. 7

                                                                                                                                                                                                            I would remove the word “Chinese”. Sony, the classic running example of a rude DRM manufacturer, is Japanese; Xperi, the shambling pile of holding companies and patents that once produced such fine product lines as Macrovision, is in the USA. Moreover, we ought to be careful when describing multinational corporate entities as loyal to any one particular government; we know from history that corporations will gladly ally themselves locally with any government willing to give them tax breaks.

                                                                                                                                                                                                            For consideration, here’s that first line with my change:

                                                                                                                                                                                                            If an application from a company installed a kernel driver onto your system with complete access to your computer, but they pinky-promised not to abuse this access and power, would you install the application?

                                                                                                                                                                                                            Isn’t that so much conceptually cleaner?

                                                                                                                                                                                                            1. 4

                                                                                                                                                                                                              I would remove the word “Chinese”.

                                                                                                                                                                                                              There’s valid concerns about the actions of the government of China. This takes into consideration actions that are still recent.

                                                                                                                                                                                                              The company is Chinese, so it is expected to comply with the requests of that government.

                                                                                                                                                                                                              1. 10

                                                                                                                                                                                                                ‘Chinese’ describes a set of ethnic identities, a set of languages, and a set of authorities.

                                                                                                                                                                                                                When I want to talk about their government specifically, I find it clearer to say “CCP” or “PRC” because it avoids dragging in the rest of those concepts.

                                                                                                                                                                                                                1. 3

                                                                                                                                                                                                                  I have flirted with this as well. I dunno. I tried “Chicom” but 1) no one knows what the hell that means 2) bc it’s from a bygone era.

                                                                                                                                                                                                                  Anyhoo, during the Cold War wasn’t “Russian” synonymous with “Soviet/USSR” in many contexts? Seems like something similar might be happening nowadays.

                                                                                                                                                                                                                  1. 3

                                                                                                                                                                                                                    I understood Chinese as about the company (the subject) being Chinese (Country the company is based on, with the associated legal framework), not about any person being Chinese.

                                                                                                                                                                                                          1. 7

                                                                                                                                                                                                            Not a completely honest comparison, unless there is a feature in paper maps that lets you use street view that I haven’t discovered yet. For some tasks, you just don’t need technology. For their particular purposes, a whiteboard or list for the grocery store still beats a any piece of technology.

                                                                                                                                                                                                            I agree with the sentiment though: I know designing is a hard job, but it feels like most designs are not thoroughly thought out, and we are layering abstraction upon abstraction without regard for the final product. Computers have gotten thousands of times faster in raw computations, which has not translated in a good user experience. We should be able to do better.

                                                                                                                                                                                                            1. 1

                                                                                                                                                                                                              Not a completely honest comparison, unless there is a feature in paper maps that lets you use street view that I haven’t discovered yet.

                                                                                                                                                                                                              I don’t see how it’s dishonest, when it’s comparing the main function of google maps – to be a digital overhead map. Street view is a cool feature, but it would entirely be possible to keep street view and redesign the google maps application to be much faster and more usable.

                                                                                                                                                                                                              1. 2

                                                                                                                                                                                                                It’s hard to pick a specific point in the article, because it seems to be mainly a rant about how Google maps doesn’t do what the author wants it to do. There are dozens of ways in which Google maps is more practical to use than a map*, and I don’t think you need me to list them for you.

                                                                                                                                                                                                                *) Probably also dozens of use cases in which it isn’t.

                                                                                                                                                                                                                1. 1

                                                                                                                                                                                                                  it seems to be mainly a rant about how Google maps doesn’t do what the author wants it to do

                                                                                                                                                                                                                  We must have read a different article, the google maps section was only a small section of the main artice.

                                                                                                                                                                                                                  1. 1

                                                                                                                                                                                                                    Yes, I meant that section, not the whole article. The article is of a similar ranty nature, though.

                                                                                                                                                                                                                2. 2

                                                                                                                                                                                                                  The interface of google maps is a digital overhead map. Thats not its primary function. Most people don’t go to google maps to find the distance between two location as the crow flies or to optimize the route of a multistop road trip. They go there to see how long their commute will take, find the nearest fast food chain and the time it closes, to see what bus transfers they need to make. And in those use cases Google Maps is vastly superior to their paper counterparts.

                                                                                                                                                                                                                  1. 0

                                                                                                                                                                                                                    Thats not its primary function.

                                                                                                                                                                                                                    Street view was a late addition to google maps. How you use google maps is different to how other people use google maps. I’ve observed both millenials, gen-xers, and gen-zers use google maps and they do not, for the most of the time, go straight to street view. In fact street view is a rarely used feature unless they’re hunting for a specific house.

                                                                                                                                                                                                                    They go there to see how long their commute will take, find the nearest fast food chain and the time it closes, to see what bus transfers they need to make. And in those use cases Google Maps is vastly superior to their paper counterparts.

                                                                                                                                                                                                                    Google maps is, as mentioned, substandard for doing that already, for the same reasons as mentioned in TFA.

                                                                                                                                                                                                                    1. 2

                                                                                                                                                                                                                      I’m not GP. And I almost never use street view.

                                                                                                                                                                                                                      How you use google maps is different to how other people use google maps.

                                                                                                                                                                                                                      That’s exactly my reaction to the article. Google maps supports a ton of different features and exposing it all in a simple understandable UI to the user is a difficult problem. Design involves tradeoffs and sacrifices. Complaining that the interface Google Maps is worse than paper maps for his specific use case is not interesting without bringing forth ideas of their own. What would a UI to cross reference data look like? Does he want a pen and ruler tool for drawing on the map? If Google maps switched to a keyboard controlled interface is there not the equally valid rant waiting, “Why does the map randomly jump around as soon as I touch a key????”