1. 2


    (for/fold ([p #f]
               [cnt 0]
               [counts null]
               #:result (cdr (reverse (cons `(,p ,cnt) counts))))
              ([c (in-string "aaaabbbcca")])
      (if (equal? p c)
          (values c (add1 cnt) counts)
          (values c 1 (cons `(,p ,cnt) counts))))
    1. 1

      Also using fold, with mnm.l :

      (def challenge (IN)
          (foldr (\ (C ACC)
                   (let ((((V . N) . TL) . ACC))
                     (if (= C V)
                       (cons (cons C (+ N 1)) TL)
                       (cons (cons C 1) ACC))))
            IN NIL))
      1. 1

        Racket’s group-by is wonderful but I usually want to group consecutive equal items into clumps as they arise rather than a single monolithic group.

        (define (group xs)
          (match xs
            [(cons x _)
             (define-values (ys zs) (splitf-at xs (curry equal? x)))
             (cons ys (group zs))]
            [_ null]))
        (define (encode xs)
          (for/list ([x xs])
            (list (first x) (length x))))
        (encode (group (string->list "aaaabbbcca")))
      1. 0

        I’d argue that types are a terrible solution to the actual problem.

        I’d argue the actual problem is, we need to check variables in our languages, for instance for someone’s age, we almost certainly don’t want -32768 as a possible age, as that makes zero sense. Also an age of 32768 is also probably equally stupid.

        we want age to be an integer between 0 and 120 or so. Certainly < 200. That’s what we actually want.

        We can argue about the upper and lower bounds of the age variable, depending on the program being written(i.e. an age of 120 for a program about the romans would be laughable, since they never lived remotely that long). But I hope we can all agree there should be upper and lower bounds for our variables.

        Types, basically don’t do that, and practically every language ever written skips over any sane way to have limits on our variables besides basically int8, int16 and string.

        There are some attempts, Liquid Haskell has a way. Postgres does this pretty well with the check constraint(though it’s not a programming language, obviously). Nim recently got ‘DrNim’ that attempts the same thing. Most other languages fail.

        1. 8

          Types do that. Commonly the pattern looks like having a constructor function that validates the machine type, like smart constructors in Haskell. (Though, as cgenschwap already noted, dependent types can do this in a quite different way.)

          1. 2

            I think you meant types might be able to do that. so I agree, in theory, types can grow to specify constraints, but other than Haskell(with multiple competing solutions apparently) and now Ada(thanks @weinholt), nobody’s type system has this ability that I’m aware of(I’m sure there are some weird esoteric languages out there that do..).

            But no commonly available/used language has anything resembling a way to sanely do constraints. The best you can do is writing a check function and calling it all over the place, hoping you don’t miss a place and your constraint fails to hold, with no warnings if you miss a spot. Languages aren’t immune to the problem, even most databases, except some SQL ones(like PG’s check) pretty much punt on constraints, so it’s a very wide problem.

            Even web frameworks, mostly fail at checking constraints, and it’s rare to see web code in the wild do much beyond the occasional JavaScript-based client-side validation of inputs. Otherwise the most you will see is ‘yes input validation is important’, but almost nobody is doing it. It’s hard, it’s not taught in programming classes or books or documentation(for the most part) and languages by and large punt on the issue.

            I’ve read a few haskell learning sites, and a book, though I’ve never programmed anything useful in Haskell, and I’d never heard of smart constructors before, so even when it’s available, nobody apparently uses it.

            Anyways, the goal here, from my perspective, is we desperately need to validate inputs, and store data with known constraints, and with rare exception, no code does this, and no commonly used languages make this remotely easy. so I think my point stands, constraint checking is still very much not done in the wild.

            Thanks for teaching me about Smart Constructors! :) I <3 learning new things!

            1. 8

              Pascal also supports it:

                Age = 0..200;
              1. 4

                Smart constructors are definitely not in the “nobody uses it” category. They are one of the most pervasive patterns in strongly typed languages (especially ML descendants like Haskell or Scala).

                1. 2

                  Smart constructors are just functions that build values of the required type, but perform some extra checks when the value is constructed…

                  It seems like you could employ the same smart constructor pattern in many languages. For the age example, you’d create a type for the valid age range and use this type elsewhere in your code:

                  class Age {
                      final int value;
                      Age(int value) {
                          if (value < 0 || value > 120) {
                              ...raise exception
                          this.value = value;

                  This is along the lines of cgenschwap’s recommendation of preferring parsing over verifying.

                  1. 1

                    You’d have to make sure the setters and getters did the checking as well along with making sure there was never any access to the internal value other than by the setters and getters. Which is a lot more faff than having it supported natively.

              2. 7

                Aren’t you just talking about dependent types? I don’t think this is a situation where languages “fail” per se, but more that it is a technically difficult thing to do (while also having a language that is easy to use for regular programmers/programs).

                Dependent types are just an extension of types – so they are certainly a good solution to the actual problem!

                1. 1

                  Dependent types is one way to do this, though so far I’ve never seen that built into a language and usually a very complicated way.

                  But who uses dependent types? no languages really have them built-in, certainly no commonly available/used languages. Haskell, has Liquid Haskell and per pushcx smart constructors also does this, apparently. Are Smart Constructors built-in? It seems like they are, but my Haskell on this machine won’t compile it, but it’s also a really old Haskell, so that could be why.

                  I agree bolting constraints onto our existing type system(s) is very complicated and messy.

                  I’ve never seen any code out in the wild that does anything like this.

                  We all know we can’t trust whatever the user gives us, and the giant list of security vulns just enforce the point, and yet basically no language in common use has any nice sane way to handle these sorts of issues.

                  1. 3

                    If dependent types interest you, the answer to “who uses dependent types” is idris

                    1. 2

                      It is unfortunate that few languages have dependent types – I completely agree with you here. However, putting constraints on user input isn’t really an issue in my opinion. You should always parse the info from the user rather than verify it.[1]

                      Raw user input is stored in a Raw{var} type (which can’t be trusted) and is parsed (with constraints) into a {var} which can be used without fear. Of course, this doesnt guarantee the data is valid – your code might still screw it up – but this concept can just be used every time the data is mutated.

                      Dependent types are fantastic because they turn this into a compile-time guarantee. Otherwise I don’t really see the benefit of having a language feature like this at runtime, it is very easy to do yourself.

                      [1] https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/

                      1. 1

                        I think you and I are in complete agreement here about the end goal. I’ve read that post before, and while what they write is possible in Haskell, basically never used(from my very limited Haskell experience), in other languages it’s a giant PITA.

                        No popular JSON parser will let you add constraints to your parsing of JSON(that I’m aware of).. The most they will do is sort of let you say this must be an int64, or this must be a string. Obviously JSON is just one example here. I’m sure there is one or two very generic parsers that allow for constraints at parsing time, but I’m not aware of any in popular languages that make adding actual constraints easy, or even possible.

                        1. 1

                          Certainly with strong, static typing this is easier to enforce (functions only take the parsed version of input). However every language can do this, it just becomes a matter of code hygeine. If JSON parsers dont let you add constraints then you just add another parsing step which can apply constraints.

                          Sure this adds boilerplate and complexity, but I would argue that this is fairly easy to do.

                  2. 6

                    I’d argue that types are a terrible solution to the actual problem.

                    I’d argue the actual problem is, we need to check variables in our languages…

                    …we want age to be an integer between 0 and 120 or so. Certainly < 200. That’s what we actually want.

                    Let me make sure that I understand what you’re asserting here: you believe that there’s only value in type systems insofar as they can allow for constraining numeric types to a bounded range? And, all languages with static type systems which fail to do this are fundamentally failures?

                    1. 0

                      No, Types are awesome for compilers, to make things go fast and optimize their implementation. There is a reason types got invented in the first place. It’s hugely easier for a compiler to optimize number math if they don’t have to concern themselves with if it might also be a string “happy”.

                      I argue though that they are pretty terrible for end programmers, because they lack constraints. There is a reason Python and friends, who mostly ignore types are hugely popular.

                      I only picked age as a very easy, hard to dispute example, but I believe constraints should apply to all data types, not just numeric types. pay period date constraints on a timesheet would be another easy use-case that doesn’t use numbers, but dates.

                      PostgreSQL’s check syntax is what I’m after here, before anything can get stored in the table, it has to be verified for sanity. but PostgreSQL is the wrong place to do this, it needs to happen way out near the user, so it’s way, way easier to say “hey user, “first” is not a valid number in the range 0-100, since this is an input for age.” So when we go to store the variable in our program, we need to be able to parse it and constrain it and verify it’s sane before anything else can happen. We as an industry completely fail at this, for the most part.

                      1. 3

                        Yes and no. There is a lot of benefits to types, they help when writing code by pointing out bugs before the code is running (contrary to Python for example). Depending on the type model you even get theorems for free, i.e. you can prove theorems about functions just from it’s type signature! That’s pretty neat.

                        Another problem is the overly structured data you’re proposing: What if I’m 106 and want to register for your service? What if I don’t have a first name? What if I don’t have a street address and live “2 mi N then 3 mi W of Jennings, OK 74038”? What if, in a family tree program, a person wants to input a child which he had with his daughter?

                        I’m not saying no constraints is a better approach, but there are a lot of edge cases to be thought of, even for something as simple as an age or a name, which maybe shouldn’t be restricted at all.

                        1. 2

                          There are new things being added to types to make it better, I agree, dependent types one of them. Like the OP post says, many type systems are hard to reason about.

                          I agree gross errors are caught trying to shove a string into an int8 variable. But academic papers disagree over how useful types are in practice, it’s mostly just yelling opinions across the internet these days, as far as I can tell. Perhaps over time, academic papers will have better science involved and eventually figure it out, but I think we can all agree the answer , scientifically speaking, is murky at best[0]. That said proving theorems sounds pretty neat!

                          Of course there are lots of edge cases with data validation/parsing, the known issues here, are multitude. I don’t have a street address most of the time. That doesn’t mean we should punt and give up on the problem, and let everything be free-form text fields. :) It’s very, very hard to reason about free-form text fields.

                          Every application will likely need unique constraints around particular data, depending on the context, but I think sane defaults can be found for many use cases. In my OP I covered this already. We can argue where the limits need to be, but for most applications I think we can agree negative ages, and ages over 150[1] are probably sane defaults.

                          If you buy into the parse vs. validate debate[2], we can’t even currently parse with any sanity. OpenBSD mostly punts on sane parsers and just assumes they are totally broken by sandboxing the parsers from the rest of the application(sshd, tcpdump as examples). I also mentioned in a different comment about JSON parsers as an example.

                          0: http://danluu.com/empirical-pl/

                          1: https://en.wikipedia.org/wiki/Oldest_people

                          2: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate

                    2. 5

                      Types, basically don’t do that, and practically every language ever written skips over any sane way to have limits on our variables besides basically int8, int16 and string.

                      I believe that Ada handles this in a good way. You can declare an age type that has a valid range of 0 .. 120. I don’t have direct knowledge of this, but AFAIK it uses a combination of static and dynamic checking. Those cases which are impossible to verify with a static checker are verified at runtime.

                      1. 3

                        Pascal and Common Lisp are two other languages with this feature, just for completeness. They’re called “subrange types” in Pascal.

                        1. 2

                          Yep, Ada can do this. You can also use a regular integer type with contracts and use Spark (the Ada subset) to prove that the integer is in the range you expect it to be, thus guaranteeing that your program is free from runtime exceptions.

                          Ada has some pretty cool features, it’s sad that nobody knows about them.

                        2. 4

                          You might find Racket’s contract system interesting. Also this talk if you have ~40 minutes (assuming 1.5x speed).

                          1. 1

                            Neat! So I agree in non-popular languages, this is sort of only recently being addressed, to some degree or other, with varying degrees of implementation. Most documentation ignores the problem. I’ve never used Racket, but Haskell is the other commonly known language that has this ability to some degree, yet I’ve never seen any Haskell code in production that uses any of the features available. Is using the contract system actively used in Racket?

                            I went looking through github, seems Pollen is popular for something written in racket, and it uses ‘provide’! [0]

                            It seems however, it’s limited to modules only.

                            0: https://github.com/mbutterick/pollen/search?q=provide&unscoped_q=provide&type=Code

                            1. 3

                              Yes, the majority of Racket code uses contracts extensively and they are also used in documentation. Some examples:

                              provide is just Racket’s way of exposing bindings from one module so that they can be required by another. The contract library provides the contract-out provide transformer that attaches contracts to bindings when they are provided. You’re right that when someone uses contract-out, then that contract will only be enforced at module boundaries. However, that’s not the only way to attach a contract to a value. The same library also provides define/contract among other things so you can do stuff like this within a single module:

                              #lang racket
                              (define smallint/c (integer-in 0 255))
                              (define/contract (f x)
                                (-> smallint/c smallint/c)
                              (f 42)
                              (f 1024)

                              Running the above yields:

                              f: contract violation
                                expected: (integer-in 0 255)
                                given: 1024
                                in: the 1st argument of
                                    (-> (integer-in 0 255) (integer-in 0 255))
                                contract from: (function f)

                              Or even stuff like:

                              #lang racket
                              (define smallint/c (integer-in 0 255))
                              (define/contract (f x)
                                (->i ([in smallint/c])
                                     [out (in) (=/c (add1 in))])
                              (f 42)

                              That yields:

                              f: broke its own contract
                                promised: (=/c 43)
                                produced: 42
                                in: the out result of
                                     ((in (integer-in 0 255)))
                                     (out (in) (=/c (add1 in))))
                                contract from: (function f)
                                blaming: (function f)
                                 (assuming the contract is correct)

                              It’s been a while since I’ve done any Haskell, but I don’t think there’s anything quite like this in the language. I definitely recommend watching the talk I linked to because it explains some of these ideas in a visual way and much better than I could do here.

                              I believe Clojure is also adopting some of these ideas now via spec, but I haven’t looked into it.

                              1. 1

                                <3 Thanks!! This looks very awesome! Go Racket!

                                1. 1

                                  <3 Thanks!! This looks very awesome! Go Racket!

                            2. 2

                              I believe you’re looking for dependent types as in eg Idris: https://en.wikipedia.org/wiki/Dependent_type

                            1. 2

                              I want to see a language with a built-in mechanism for this kind of ambient context. Something strongly-typed, that allows application developers to supply context values that “follow” across things like async “callLater” type deferrals, as well as being useful for structural “container” hierarchies like eg something like a react context.

                              But I don’t want it just as an alternative to explicit call parameters, I’d also like to be able to push/pop contextual information for debugging, which would be available when running in debug-mode alongside a regular stack trace.

                              1. 2
                                1. 1

                                  Common Lisp has special variables, which are exactly for dynamic context. Regarding type, you can always just DECLAIM or PROCLAIM a type for the special variable.

                                1. 15

                                  Every now and then I’ll visit a website, notice there’s nothing new since I last visited and then absent-mindedly hit cmd+L, type the website URL in and visit that same website again within the span of 30 seconds. It’s, uh, a problem.

                                  1. 3

                                    SELECT ... FOR UPDATE SKIP LOCKED was introduced in Postgres 9.5 to solve (some of) these issues. With it, dequeueing a set of jobs looks like this. No need to hang on to a long running transaction either as long as you have some sort of process to requeue dropped jobs.

                                    1. 1

                                      The article was published in 2015.

                                      1. 1

                                        Oh, I wasn’t aware it got fixed in Postgres 9.5. However, I still do like the article as it goes into depth on various intricacies of Postgres and gives a good insight on how things work. A good, albeit outdated, learning material.

                                        1. 1

                                          It doesn’t however solve the “dead tuples problem” mentioned in the article. Correct me if I’m wrong.

                                          1. 2

                                            That’s right. That’s an issue for any table that has high churn in terms of updates and deletes and that’s something you’d work around by tuning auto vacuum (to run frequent, fast vacuums – the goal being predictable performance over very high throughput) and things like the fillfactor for the jobs table specifically.

                                            Another option I’ve heard about but never tried is having two jobs tables and periodically switching between them and truncating the other. Presumably, that’d involve turning off autovacuum for the two tables since you’re effectively performing a full vacuum “in software” at every switch. Personally, I think that if you get to the point where you need to do something like that, it’s probably time to move on to a real message queue (like RabbitMQ).

                                        1. 4

                                          Interesting. Any experience with cross-compilation? Apparently there’s:


                                          But doesn’t appear to have a lot of convenience around it (eg: no “raco add-target win64; easily compile for win64”)?

                                          1. 2

                                            I’d never tried it before, but it seems to work great. I downloaded a build of Racket CS for linux to ~/Downloads/racket and then ran the following:

                                            $ racket -C -G ~/Downloads/racket/etc -X ~/Downloads/racket/collects -l- raco exe -o app app.rkt
                                            $ file app
                                            app: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=7fbdabb07e54037e2ede76daf74d7ecfdcc5b486, stripped
                                            $ racket -C -G ~/Downloads/racket/etc -X ~/Downloads/racket/collects -l- raco distribute dist app
                                            $ tree dist/
                                            ├── bin
                                            │   └── app
                                            └── lib
                                                └── plt
                                                    ├── app
                                                    │   └── exts
                                                    │       └── ert
                                                    │           ├── r0
                                                    │           │   └── example.txt
                                                    │           ├── r1
                                                    │           │   └── error.css
                                                    │           ├── r2
                                                    │           │   └── dh4096.pem
                                                    │           └── r3
                                                    │               └── bundles
                                                    │                   ├── es
                                                    │                   │   └── srfi-19
                                                    │                   └── srfi-19
                                                    └── racketcs-
                                            12 directories, 7 files

                                            Someone could definitely make this easier by providing a package to add a raco command like the one you’ve suggested.

                                          1. 6

                                            Thank you for writting this.

                                            With regards to distribution options with racket,

                                            Is there a way to ship platform independent, but hard to reverse engineer ‘precompiled’ binaries ?

                                            For example for deploying closed-source software into a private enterprise (where the servers are controlled by customers)

                                            1. 6

                                              Racket CS modules are compiled to native code so you can ship those around and reverse-engineering them would be about as hard as reverse-engineering any other natively-compiled code. You’d have to compile these separately for every platform you want to target. I believe there’s a way to ship modules in “linklet” form, which is platform-independent, and Racket CS will convert those to native code on first run, but I’ve never tried it.

                                              Here’s the output of running raco decompile on the compiled version of the app in the post: https://gist.github.com/Bogdanp/64a7ef659d6376fff918e3cb23518f9b

                                            1. 2

                                              Shameless plug: there’s also nemea which I wrote and use for all my stuff.

                                              1. 1

                                                cc @soapdog. This seems relevant to your Gemini browser!

                                                1. 13

                                                  https://defn.io - I mostly write about Racket.

                                                  1. 3

                                                    Your blog helped me a lot with Racket. Thanks a ton.

                                                    1. 2

                                                      Subscribed to your RSS feed a while ago, I learned a lot about racket thanks to you!

                                                      1. 2

                                                        I remember your post about using Racket to write an e-commerce platform. I thought that was awesome!


                                                        1. 1

                                                          @jee @Artemix @soapdog glad to hear it! Thank you!

                                                        1. 8

                                                          Finishing up my talk and tutorial in preparation for Racketfest next week!

                                                          1. 9

                                                            This is really good news. I will admit I’m a bit disappointed that it’s currently at best about as fast as the original. I’m glad to hear they have a plan to help address this though. The future does look bright.

                                                            1. 1

                                                              currently at best about as fast as the original

                                                              Based on the note about the relative performance of indirect function calls and continuations, I think the impact for Real™ applications is probably understated. Anything that makes heavy use of exceptions and threads (both implemented using continuations), should be faster than in Racket BC.

                                                              To test this, I ran some local perf. tests to measure the difference in throughput of the web-server-lib between CS and BC and I saw a significant increase in throughput under CS. If I find some time next week, I might clean up and publish the results.

                                                            1. 5

                                                              Does Chez compile to native code like Chicken? Would it be possible to produce statically linked binaries with musl or similar for the C runtime?

                                                              1. 1

                                                                Yes to the first question. I think the second should be possible, but I’m not sure what the level of effort required is.

                                                              1. 22

                                                                For me, Catalina worked fine since I’ve installed Beta 2 last summer.

                                                                Even the usual suspects, VMWare, Vagrant/VirtualBox and Homebrew survived the update just fine.

                                                                I see no crashes (at least not more than the usual once-every-two-months need to reboot), nor other weirdness. Compared to Mojave, even the random Bluetooth disconnects I had with my Magic Trackpad stopped happening.

                                                                Of course this is total non-news and I’m not going to publish a blogpost saying that Catalina is fine for me nor would that reach, much less survive on, the front page of any news aggregator if I actually were to write such a blog post.

                                                                Unfortunately, we only read about people having issues and we conclude that everybody must have problems.

                                                                1. 6

                                                                  Hear hear! I think we should share our positive experiences more often, since it’s in our nature to latch on and to spread the negative ones.

                                                                  1. 3

                                                                    I think we should share our positive experiences more often, since it’s in our nature to latch on and to spread the negative ones.

                                                                    From the article:

                                                                    It’s interesting to me how — apart from the usual fanboys — I still haven’t seen any unequivocally positive feedback about Mac OS Catalina.

                                                                    Is your experience positive (it got better) or is your experience neutral (it didn’t get worse)? What is the best thing about Catalina, and what would be the elevator pitch for why somebody should install it?

                                                                    1. 3

                                                                      apart from the usual fanboys

                                                                      I certainly wouldn’t consider myself an Apple fanboy, but when I look at the current state of all the other platforms, nothing comes quite close enough for what I need and like.

                                                                      Is your experience positive (it got better) or is your experience neutral (it didn’t get worse)?

                                                                      I take issue with the implication that things chugging along just fine is somehow not a positive thing. I was doing well yesterday, and I am doing about the same today. Not better and not worse. Am I somehow worse off today because of that? If I am not worse off, then is my experience not positive?

                                                                      What is the best thing about Catalina, and what would be the elevator pitch for why somebody should install it?

                                                                      Two things sprung to mind immediately:

                                                                      • I was pleasantly surprised both this week and the week before that the OS notified me of my daily average use of the computer over the prior days. The numbers were, unsurprisingly to me, extremely high. I knew I was spending too much time on the computer recently, but the computer itself giving me hard numbers is what finally convinced me to take steps toward spending less time on it.

                                                                      • I really appreciate the increased security that notarization brings. Hell, I’ve even written a native app and gotten it sandboxed, notarized and deployed on the App Store so I’ve experienced more “pain” than the average Catalina user in this regard, yet I still think it’s a fantastic improvement.

                                                                      1. 1

                                                                        That looks super interesting.

                                                                        I really like separating any UI-application in a client-server layer, to avoid accidentally letting business logic, heavy computation, and blocking IO to creep into/block the UI threads (something I’ve seen happen with many QT-based GUI-application). The risk of this is heavily reduced by making the barrier more concrete through separate processes with RPC, while also adding opportunity for more resilience since the client and server process can be restarted separately if an issue occurs.

                                                                        Would be interesting to see some more details of the GUI/Swift part of the application for someone not familiar with that toolchain, are you planning to write more articles in this series?

                                                                        1. 1

                                                                          Thanks! Yes, I do plan to write more about the technical bits of the app in the future. I think I’ll do another post after I’ve got the Windows port ready. I’m thinking it would be fun to compare Windows Forms and SwiftUI in a post. It might be a while before I get to it, though, because I’m juggling a ton of stuff at once at the moment.

                                                                          In the mean time, the application is source available so you can take a look at the GUI code here.

                                                                          1. 1

                                                                            Interesting, looking forward for it.

                                                                            Are you planning to showcase how you work with XCode? Would be nice to get a overview of how the workflow looks for these kind of apps.

                                                                  2. 3

                                                                    same experience here. I have encountered some crashes on my work laptop, but since I’ve had zero issues on my home laptop, I’d much sooner attribute that to my employer’s custom management software than the OS itself.

                                                                  1. 3

                                                                    Racket CS is ready for production use.

                                                                    Very cool! This blew my mind when I first heard about it.

                                                                    1. 1

                                                                      What does this mean to racket? Will this make the executables fast or does it make the compilation fast?

                                                                      1. 2

                                                                        The latest report talks about this in some detail. Some things are faster, some slower and the slow things are going to get better in time. Compilation times are longer.

                                                                      2. 0

                                                                        Why? From what I’ve seen, they’ve done much more mind-blowing things than re-basing Racket on Chez?

                                                                        1. 3

                                                                          One should not trivialize the amount of work that went into porting all of the macro shenanigans to Chez, and the amount of compatibility bridges that needed to done (see figure 3 in this document) to actually make it compatible, semantically.

                                                                      1. 16

                                                                        To give a counterpoint to the other, negative, comments: I upgraded from High Sierra to 10.15.2 and I have had no problems thus far. The notarization requirement is somewhat annoying, but, ultimately, I appreciate that it exists and, personally, I like that I get to specifically give (or not) access to various parts of the filesystem per app.

                                                                        1. 2

                                                                          The one I built. It only does what I need (aggregate counts, referrals, live counters) and it does it well. For a real world deplyoment, see: https://defn.nemea.co

                                                                          1. 3

                                                                            We’ve got an extended weekend over here so I’ve started adding DB sync support to Remember and, once that’s done, I plan to get started on the Windows version.

                                                                            1. 3

                                                                              Nice architecture! I have to confess that I was a wee bit disappointed, because I misinterpreted the title. I expected a native GUI defined in Racket; but in fact it’s a platform-agnostic core written in Racket, plus a native GUI written in another language (Swift).

                                                                              Still, a very nice architecture, and I hope you get the library version with in-process interop working, too. Good luck, and have fun!

                                                                              Edit to add: your architecture, with a platform-agnostic core and a platform-specific front-end, reminded me a lot of Simon Tatham’s portable puzzle collection (enough that I went to look it up for you, and the figured I might as wel submit it to Lobsters). That project has game-specific backends, platform-specific frontends, and both-agnostic middleware that lets the games and the platforms compose to give m × n combinations. The architecture and the problem it solves are a bit different from yours, but perhaps there are enough parallels to make it relevant.

                                                                              1. 2

                                                                                Thanks! I can see how the title might be interpreted that way. I should’ve added “at their core” to the end or something.

                                                                                Those puzzles look really cool, thanks for the link.

                                                                              1. 4

                                                                                Racket would have to be able to target arm64 for that to be feasible

                                                                                It does. Without JIT, only interpretation, but works fine.

                                                                                1. 2

                                                                                  Interesting! I had no idea. Do you have any links I could take a look at?

                                                                                  1. 2

                                                                                    I don’t have any links. On normal desktop/server aarch64 platforms, you (or the OS packager) just compile it as usual (without --enable-jit) and it just works. It’s cross-platform.

                                                                                    1. 3

                                                                                      Sweet. I’ll have to play around with that. I’ve updated the article. Thanks!

                                                                                      EDIT: Turns out there is info about cross-compilation to iOS and Android in the Racket source README: