2021-05-15 21:06:00 UTC: We're in read-only mode for probably ~30 minutes for a database migration. Join #lobsters on freenode or follow the todo list.

  1. 6

    Over the weekend i finished integrating CoreData with a reminder/todo app I am writing for myself.

    This week I’ll try to add reminders support to the app.

    side note: learning iOS development with Swift UI is pretty painful, the docs are incomplete, all the posts are from different versions of the API and i don’t have the patience sit and read all docs to find what I need.

    1. 2

      CoreData, although very versatile and powerful, seems overly complex for simple apps that just need a basic, secure data store. Especially if you’re building an Apple Watch app. Actually was very discouraging when I was trying to whip up a quick PoC of an idea a few weeks ago. What’s your take?

      Also, I loved Swift when it first came out. But after revisiting it years later…has it become a bloated language or what. So many decorations and ways to do the same thing…I feel like I’m in a Party City (I don’t like shopping for party stuff).

      1. 2

        I agree with both of your points, CoreData is complicated but the value it provided me is high. I think once i had the Objective-C style delegate listening for updates, then i didn’t have to touch it again.

        Swift is too bloated or Swift UI uses too much, i was confused with @State, @StateObject and the million combine annotations.

        I am more of a Go style engineer, i like thing simple and my brain can’t handle too much bloat. Minor things like trying to discover which package provides which struct is a PITA. (is @Published from SwiftUI import or Combine…)

        But after a day and a half of struggling, looking for examples, i think i finally get it enough to not want to rm -rf the project and move on. I might spend a few days lightly reading the docs for both swift ui & combine after finishing the project if they are not deprecated by then….. feels like i am in js land all over again.

        1. 2

          As a go engineer who has tried a few weekends of swift, my experience was very similar. Especially about incomplete docs and outdated examples. I really feel like the barrier to becoming fluent & productive is unnecessarily high, perhaps if i could dedicate a few weeks to nothing but iOS dev i could get somewhere.

    1. 30
      • RISC-V CPUs. Because open standards encourage co-operation across borders.
      • Zig. Because people want to replace C with something more secure, but in a gradual process, and Zig includes a C compiler.
      • MIDI over Bluetooth 4. Because it’s handy.
      • The Gemini protocol, since retrominimalism is still fun.
      • Godot for game development, because it has matured enough.
      • TOML since it seems to be the least disliked configuration format.
      1. 5

        Godot is in a great spot and just keeps getting better. I’m hoping you’re right on this one!

        1. 2

          “…encourage co-operation across borders” well said! I actually never considered geopolitical impact with processors. could you point me towards some reading, or share insight?

          1. 2

            I’m not an expert on RISC-V, but I know that both MIT and China work on improving it. There’s also political will in Europe to build a European CPU.

          2. 2

            MIDI over Bluetooth 4. Because it’s handy.

            Had to look that up. Latency jitters between 3-10ms. Figures.

            1. 1

              3-10 ms is acceptable latency for MIDI though?

              1. 4

                Drummers will disagree.

                But even then, It isn’t just 3-10ms latency; It is the latency from bluetooth + whatever other latency in the latency chain.

                It all adds up.

                1. 5

                  (Am drummer) A total latency, i.e. of the whole chain, of 3-10 ms is okay. 3-10 ms for a single MIDI message is 3-10 times more than one would expect :-). Also, jitter matters enormously. A constant latency of 20 ms is annoying, but you can sort of live with it if you really try. Constantly jittering between 5 and 20 ms, on the other hand, feels like you’ve had one too many drinks.

            2. 1

              Two months later, RISC-V, TOML, Gemini and Godot has good traction and Zig is still very promising (and under development - not Rust-levels of safety yet).

              MIDI over Bluetooth, on the other hand, has delay and setup issues. I’ve tried it and I have lost faith in it.

              1. 1

                Three months later, there are some MIDI over Bluetooth hardware solutions that claim to be able to send signals with a 3ms delay. I tried the CME WIDI device. So far, it has been a complete hassle to set up on my Android phone, but the delay is very low. It also feels fine to play with a MIDI controller connected to a Linux machine, where Jack then redirects the MIDI signal via Bluetooth to the WIDI device.

            1. 6

              This question was prompted by a discussion I had about how I felt like all the momentum in programming languages is pointing toward Rust these days, and I felt like there’s no point in keeping my Go current (it’s been languishing for a couple of years now anyway).

              So, I asked this question to see (among other things) if I’m right or wrong.

              1. 12

                What is driving that feeling? Genuinely curious, because I feel the opposite. I am seeing more and more enterprises adopt Go. In conversations I have with other engineers, Rust still feels a little underground.

                I also think that Go and Rust have slightly different use cases & target audiences.

                1. 9

                  Well, lobste.rs, for one. I feel like everywhere I look on here people talk about how they’d re-do everything in Rust if they could. The number of Rust advocates I see here seems to dwarf the number of Go advocates. Maybe that’s perception because Rust is “newer” and its advocates louder, but who knows.

                  The things that really stuck with me, though, were Linus indicating that he’d be open to allowing Rust in the kernel, Microsoft starting to switch to Rust for infrastructure, and Dropbox migrating their core technologies to Rust.

                  I just don’t see stories like that for Go. I don’t know if I’m not looking in the right place, or what.

                  1. 22

                    Go and Rust more or less solve the same problem (although the overlap isn’t 100%), just in different ways, not too dissimilar to how Perl and Python more or less solve the same problems in very different ways.

                    I have the impression that, on average, Go tends to attract people who are a little bit jaded by the Latest Hot New Thing™ churn for 20 years and just want to write their ifs and fors and not bother too much with everything else. This is probably one reason why the Go community has the (IMHO reasonably deserved) reputation for being a bunch of curmudgeonly malcontents. These are not the sort of people who go out and enthusiastically advocate for Go, or rewrite existing tools in Go for the sake of it: they’re happy with existing tools as long as they work.

                    Another reason I don’t really like to get involved in Go discussions is because some people have a massive hate-on for it and don’t shy away from telling everyone that Go is stupid and so is anyone using it every chance they get. It gets very boring very fast and I have better things to do than to engage with that kind of stuff, so I don’t. There’s some people like that on Lobsters as well, although it’s less than on HN or Reddit. It’s a major reason why I just stopped checking /r/programming altogether, because if the top comment of damn near every post is “lol no generics” followed by people ranting about “Retards in Go team don’t think generics are useful” (which simply isn’t true) then … yeah… Let’s not.

                    1. 14

                      Go and Rust more or less solve the same problem

                      Hard disagree, rust is way more useful for actual problems like c/c++ are. I can write kernel modules in it, there is almost no way i’d want to do that with go. Having a garbage collector, or even really a runtime in go means a different use case entirely to being able to run without an os and target minis. Yes I know go can be used for that too but just due to having a GC you’re limited on how far down the horsepower wagon you can go.

                      I hold no views outside of that rust actually has solutions and community drive (aka people using it for that upstreaming things) for programming things like avr processors etc… I don’t hate go it just strikes me as redundant and not useful for my use cases. Kinda like if you learn python not much use for learning ruby too kind of a deal. And if I’m already using rust for low level stuff, why not high level too?

                      I don’t however miss debugging goroutine and channel bugs though, go is way easier to shoot yourself in a concurrent foot without realizing it. It might be ‘simple’ but that doesn’t mean its without its own tradeoffs. I can read and write in it but prefer the rust compiler telling me i’m an idiot for trying to share data across threads to goroutine debugging where two goroutines read off one channel and one of ems never gonna complete cause the other already got it. I’m sure “I’m holding it wrong” but as I get older these strict and more formal/functional languages like rust/haskell/idris/blah strike my fancy more. I”m not talking about generics really but stuff like Monads (Option/Result essentially) read to me way better than the incessant if the thing i did isn’t nil constantly. Its closer to what I’ve done in the past in C with macros etc…

                      Its not that I hate it though, just that the language seems a step back in helping me do things. Idris as an example though is the coolest thing I’ve used in years in that using it was like having a conversation with the compiler and relearning how to move my computation to the type system. It was impressive how concise you can make things in it.

                      As a recovering kernel/c hacker, you’d think go would appeal but to be honest it just seems more of the same as c with less ways of stopping me from shooting myself in the foot needlessly.

                      But to each their own, functional languages with types just strike me as actually doing a lot of things that OO languages from the mid 90’s always said could be done with open form polymorphism but never seemed to happen.

                      In 10 years we’ll see where the ball landed in the outfield so whatever.

                      1. 11

                        Yes, hence the “more or less”. Most people aren’t writing kernel modules; they’re writing some CLI app, network service, database app, and so forth. You can do that with both languages. TinyGo can be used for microcontrollers, although I don’t know how well it works in practice – it does still have a GC and a (small) runtime (but so has e.g. C).

                        I don’t however miss debugging goroutine and channel bugs though, go is way easier to shoot yourself in a concurrent foot without realizing it.

                        Yeah, a lot of decisions are trade-offs. I’ve been intending to write a “why Go is not simple”-post or some such, which argues that while the syntax is very simple, using those simple constructs to build useful programs is a lot less simple. In another thread yesterday people were saying ‘you can learn Go in two days”, but I don’t think that’s really the case (you can only learn the syntax). On the other hand, I’ve tried to debug Rust programs and pretty much failed as I couldn’t make sense of the syntax. I never programmed much in Rust so the failure is entirely my own, but it’s a different set of trade-offs.

                        In the end, I think a lot just comes down to style (not everything, obviously, like your kernel modules). I used to program Ruby in a previous life, which is fairly close to Rust in design philosophy, and I like Ruby, but it’s approach is not without its problems either. I wrote something about that on HN a few weeks ago (the context being “why isn’t Ruby used more for scripting?”)

                        1. 4

                          Most people aren’t writing kernel modules; they’re writing some CLI app, network service, database app, and so forth. You can do that with both languages.

                          CLI yes, database probably, but I don’t think Rust’s async or concurrency or whatever story is mature enough to say it’s comparable with Go for network services.

                          1. 1

                            Cooperative concurrency is just more complicated (as a developer, not as a language designer) than preemptive concurrency. The trade-off is that it’s more performant. Someone could build a Rust-like language, i.e. compiler-enforced data race freedom, with green threads and relocatable stacks. And someday someone might. For now, the choice is between performance and compiler-enforced correctness on the Rust side, or “simpler” concurrency on the Go side.

                      2. 3

                        There’s just a lot of toxicity about programming languages out there, and subjectively it feels particularly bad here. Rust has a lot to like and enough to dislike (abandoned libraries, inconsistent async story, library soup, many ways to do the same thing), but something about its culture just brings out the hawkers. I still heartily recommend giving Rust a try, though you won’t be super impressed if you’ve used Haskell or Ocaml in the past.

                        1. 6

                          I came to Rust after having used Haskell and the main thing about it that impressed me was precisely that it brought ML-style types to language with no GC that you could write an OS in.

                          1. 5

                            with no GC

                            I guess I find this often to be a solution with very few problems to solve. It’s understandable if you’re writing an OS or if you’re working on something real-time sensitive, but as long as the system you’re making can tolerate > 1ms p99 response times, and doesn’t require real-time behavior, Go, JVM languages, and .NET languages should be good enough. One could argue that there exists systems in the 1-10ms range where it’s easier to design in non-GC languages rather than fight the GC, and I can really see Rust succeeding in these areas, but this remains a narrow area of work. For most systems, I think working with a GC keeps logic light and easily understandable. When it comes to expressive power and compiler-driven development, I think both Haskell and Ocaml have better development stories.

                            1. 1

                              Rust also has a much cleaner package management story and (ironically) faster compile times than Haskell. And first-class support for mutability. And you don’t have to deal with monad transformers.

                              Haskell is still a much higher level language, though. I experimented last night with translating a programming language core from Haskell to Rust, and I quickly got lost in the weeds of Iterator vs Visitor pattern vs Vec. Haskell is pretty incredible in it’s ability to abstract out from those details.

                          2. 0

                            Your descriptions of both advocates and Go haters match my experience exactly.

                          3. 14

                            I’ve been using Go since around the 1.0 release and Rust for the last year or so. I don’t think either of them is going away any time soon. Go has less visible advocates, but it’s definitely still used all over the place. Datadog has a huge Go repo, GitHub has been looking for Go engineers, etc.

                            Rust is more visible because it’s newer and fancier, but it still loses for me in multiple aspects:

                            • Development speed - It’s a much pickier language and is much slower to develop in, though it forces you to get things right (or at least handle every case). Rust-Analyzer is great, but still fairly slow when compared to a simpler language.
                            • Compilation speed - Go compiles way faster because it’s a much simpler language.
                            • Library support/ecosystem - Because Go has been around for quite a while, there are a wealth of libraries to use. Because Rust hasn’t been around as long, many of the libraries are not as mature and sometimes not as well maintained.

                            However, Rust makes a number of improvements on Go.

                            • Error handling - Rust’s error handling is miles above Go. if err != nil will haunt me to the end of my days.
                            • Pattern matching - extremely powerful. This is an advantage Rust has, but I’m not sure how/if it would fit in to Go.
                            • Generics - In theory coming to Go soon… though they will be very different feature-set wise

                            They’re both great languages, and they have different strengths. For rock-solid systems software, I’d probably look at Rust. For web-apps and services, I’d probably look to Go first.

                            1. 4

                              Rust also loses massively in concurrency model. Tokio streams is so subpar to channels.

                              1. 2

                                Tokio also has channels - MPSC is the most common variant I’ve seen.

                                When Stream is added back to tokio, these will also impl Stream

                                I do agree that having goroutines as a part of the language and special syntax for channels makes it much easier to get into though.

                                1. 1

                                  Rust’s async/await is definitely more complicated than Go’s green threads, and is almost certainly not worth it if Go has everything you need for your project. However, Rust’s standard threads are extremely powerful and quite safe, thanks to the Sync and Send marker traits and associated mechanics, and libraries like rayon make trivial parallelism trivial. Just yesterday I had a trivially parallel task that was going to take 3 days to run. I refreshed myself on how to use the latest rayon, and within about 10 minutes had it running on all 8 hyperthreads.

                                2. 2

                                  Spot on. They both have their annoyances and use cases where they shine.

                                3. 6

                                  A further difference is that Go code is hard to link with other languages due to its idiosyncratic ABI, threading and heaps. Rust fits in better. Not just in OS kernels but in mobile apps and libraries. (I’m still not a fan of Rust, though; Nim fits in well too and just feels a lot easier to use.)

                                  1. 1

                                    I would say that is entirely compiler dependant, and not a property of the language Go. https://github.com/tinygo-org/tinygo

                                    1. 2

                                      As long as the language has highly scalable goroutines, it won’t be using native stacks. As long as the language has [non ref-counted] garbage-collection, it won’t be using native heaps.

                                      1. 1

                                        Well, tinygo != go, and e.g. gccgo still reuses the official standard library from the main implementation (which is where lots of the frustrating stuff is located, e.g. the usage of raw syscalls even on platforms like FreeBSD where it’s “technically possible but very explicitly not defined as public API”).

                                    2. 5
                                  2. 9

                                    Golang is awesome. It works without fanfare.

                                    1. 8

                                      As someone who dislikes Go quite a lot, and is really enjoying Rust: I think they are different enough they serve different use cases.

                                      Go is much faster to learn, doesn’t require you to think about memory management or ownership (sometimes good, sometimes very very bad, Go code tends to be full of thread-safety bugs), is usually fast enough. For standard web app that is CPU-bound it’ll work just fine, without having to teach your team a vast new language scope.

                                      On the flip side, I’m working on a LD_PRELOADed profiler that hooks malloc(), and that’s basically impossible with Go, and I also need to extract every bit of performance I can. So Rust is (mostly) great for that—in practice I need a little C too because of Reasons. More broadly, anytime you want to write an extension for another language Go is not your friend.

                                      1. 4

                                        Go comes with a built-in race detector. What sources do you have for “tends to be full of thread-safety bugs”?

                                        1. 11

                                          As someone with a fair bit of go experience: the race detector only works on races you can reproduce locally, as it’s too slow to run in production.

                                          Rust stops you from doing things that can race; go gives you a flashlight to look for one after you accidentally introduce it.

                                          1. 1

                                            That is a good point, but once a developer has encountered the type of code that makes the race detector unhappy, will they not write better code in the future? Is this really a problem for most popular Go projects on GitHub, for instance? Also, the “staticcheck” utility helps a lot.

                                            1. 2

                                              Unfortunately, there’s still, even among some experienced programmers, a notion that “a race will happen so rarely we don’t have to worry about this one case”. Also I’ve seen an expectation that e.g. “I’m on amd64 so any uint64 access is atomic”, with no understanding of out-of-order execution etc. I assume in Rust this would be a harder sell… though the recent drama with a popular web framework (can’t recall the name now) in Rust seems to show to me that using unsafe is probably kinda similar approach/cop-out (“I just use unsafe in this simple case, it really does nothing wrong”, or “because speed”).

                                      2. 3

                                        I think (hope) the world settles into Rust and Go. I don’t see the Bell Labs folks not going 3 for 3 with Go. Rust I enjoyed playing with many months ago and it was a bonus I guess (at the time) that it was backed by Mozilla. Misplaced loyalties abound. Maybe (in a decade or so) lots of things once written in C will Rust over and tcp/http stuff will be written in Go.

                                      1. 14

                                        Quoting from the article:

                                        Argument: You can type out messages

                                        Surely, it’s not like you will open a terminal on your cell-phone and then type in SIP like this to call your friend.

                                        INVITE sip:1001@;transport=udp SIP/2.0


                                        While reading this, I had the distinct impression that it might be written by an application developer rather than a systems programmer, system administrator, or network engineer. I speak HTTP/1.1 pretty well. For that matter, I speak SMTP pretty well, too. If you speak SMTP, you can speak similar IETF protocols like NNTP and POP3 without much extra effort. They have a family resemblance, like Spanish and Portuguese.

                                        That ability has helped me quite a few times as an admin, but it also proved invaluable while implementing application-layer protocols.

                                        The article is thought-provoking. I remain on the fence about which is better: text or binary. Maybe the answer is both, and maybe I’d have a deeper appreciation of binary protocols if I had the right tooling.

                                        1. 5

                                          I’d have a deeper appreciation of binary protocols if I had the right tooling.

                                          Yeah, I kinda like text protocols sometimes too (though they are a real pain to correctly parse. Like there’s usually special rules for edge cases that are easy to forget.), but consider the case of assembly language.

                                          I can read a little bit of machine code off a hex dump…. but not much since there’s basically never any need since I can assemble/disassemble just about anything so easily.

                                          A binary protocol that came with such a translation thing to/from some text format would probably be the best of both worlds. And then it can be validated before sending to help catch typos too.

                                          1. 7

                                            Binary protocols have to be parsed, too: Assuming you can just bamf them into a struct is assuming that no transmission errors occurred, no errors occurred in the sending process, and no errors occurred in the machine the sending process was running on. Even if you strictly discount such things as endianness differences and differences in word sizes, there’s still parsing to be done.

                                            1. 4

                                              Binary protocols have to be parsed, too

                                              Indeed, my advice for people is often to do it byte by byte, then no more endianness problem, word size problem, etc. And things like variable length members easier to handle then too. But it still tends to be much easier to do correctly than text format parsing since there’s usually fewer weird cases to consider.

                                              1. 2

                                                Agreed assuming that one is working at a low enough layer that they actually need to consider this stuff. I’ve spent a good amount of my career working on avionics hardware & software, and a significant amount of that time was spent staring at a digital scope hooked up to a data bus trying to figure out what was going wrong before a payload even got to the point where I could try to slam it into a (properly packed and versioned) struct.

                                                However, there definitely are streamlined ways to perform quick error checking on binary payloads while they are “on the wire”. For example, parity bits and other checksum techniques. And, most of the time, this error checking is being performed at a much lower layer than the developer is actually working in.

                                                It is sometimes the case that nuanced data that would otherwise need to be parsed using costly string functions can be communicated more efficiently in a binary protocol. Bitwise (flag) lookup tables come to mind – for example, one can communicate 32 different flags in a single integer – and each of which can be checked extremely efficiently using bitwise operators.

                                                Also, from the experience of creating a couple of real-time systems (for enterprise, avionics, and multiplayer video games), binary protocols can often be a lot “nicer” to parse. If you can trust that the payload is not corrupt, then you can simply stream/scan and count – or, even better, blit and mask – rather than perform weird splits and finds while fighting off-by-one errors.

                                                1. 2

                                                  Assuming you can just bamf them into a struct is assuming that no transmission errors occurred, no errors occurred in the sending process, and no errors occurred in the machine the sending process was running on.

                                                  Adding a checksum to a binary protocol is trivial compared to adding it to a text-based one.

                                                2. 4

                                                  This is one of the reasons why I try to use standardized self-describing binary protocols like CBOR or messagepack when feasible. The more they get used the more incentive there is for people to make tools like jq that work with them.

                                                  …actually, a hex-editor type program that could display and manipulate CBOR structures would be pretty neat– no no I have enough side projects brain please stop.

                                                3. 3

                                                  I write web apps for a living, and I know how to do HTTP “by hand” and have used it for debugging. Same with SMTP. I also encourage people who want to learn backend web development to try out writing a very basic HTTP/1.1 server in their language of choice and communicating with it, to get a feel for what needs to go on.

                                                  1. 1

                                                    But for how long, now that HTTP/2 and HTTP/3 are a thing [1]?

                                                    [1] Thanks be to our new Internet Overlord, Google.

                                                    1. 1

                                                      A great tool for this is netcat (a.ka. nc). Even better is that it comes as a standard CLI utility on macOS and many Linux distros.

                                                  1. 1

                                                    MessagePack seems relevant to this conversation (see existing post on Lobsters). It claims some pretty impressive performance and payload size improvements. However, the cases where those would matter nowadays are probably few-and-far between.

                                                    1. 3

                                                      So many cool accessories were created for the Game Boy and its later models. I remember having an audio recorder + radio tuner one for my Advance SP. Plugged right into the cartridge slot.

                                                      1. 2

                                                        Thank you for this article and for embracing people’s follow-up questions here 🙂. I learned so much.

                                                        This feat and all that has gone into it (that I can’t even begin to fully comprehend) is incredible. I’m floored by what the world has pulled off this year. Amazed and thankful.

                                                        1. 9

                                                          This reminds me of http://vanilla-js.com/ 😉. I do agree with the sentiment when possible though – keep your footprint as small and sleek as possible so long as it doesn’t cripple your ability to maintain and scale.

                                                          1. 3

                                                            That’s amazing

                                                            1. 1

                                                              My favorite part about this website has always been that the gzipped version is 25 bytes due to the compression header. I think I checked once they it was correct by gzipping an empty file.

                                                          1. 3

                                                            There are two downsides that we’ve run into with poll-only approaches ↝

                                                            1. It puts undue, often unscalable load on the source system.
                                                            2. It makes for a less real-time system (not always an issue).

                                                            Increasing and staggering the poll interval helps with the former, but amplifies the latter.

                                                            We’ve found that a hybrid approach leveraging a pub/sub model works well. Consumers subscribe to updates from the source system that they care about. When an update occurs, the source system publishes an event stating so, and the consumer can choose at that point to inquire for more information required to sync itself up. The consumer also polls with a long interval to guarantee that, even with degradation, it eventually syncs back up using a traditional, resilient mechanism.

                                                            General rule of thumb that we’ve followed for events (learned from many financial exchange’s real-time APIs) ↝ events should have enough information to support the majority of use cases without requiring the consumer to make another inquiry, and enough information for the consumer to specifically inquire for the remainder of the information in the minority of use cases.