I happen to be studying Korean at the moment, so this is interesting to me, but I think it would have been good to have added Romanization of the Korean text.
Yes! I gave up reading, actually, because it took too much effort to try to match the unfamiliar glyphs in the examples.
I can give the examples in Japanese, since they’re basically identical (in terms of grammar and syntax) for these examples.
“I eat rice” would be “watashi (I) wa (load-topic
) gohan (rice) o (load-target
) tabemasu (invoke-eat
)”. You can see how we keep saying a noun, and then loading it into the appropriate register.
I honestly don’t remember anymore how to do the subordinate clause in the second example, but the word order would end up being close to “I load-subject
yesterday rice set-object
ate push-clause
load-topic
delicious assert-equal
. The Korean example should be extremely close.
In Japanese, the subordinate clause example should be:
私が昨日食べたご飯は美味しかった。 watashi ga kinou tabeta gohan wa oishikatta
[I (subject) yesterday ate] rice (topic) was-delicious. = The rice [I ate yesterday] was delicious.
I am not sure if Korean has the same word order in this example.
Germanic languages other than English can achieve a similar word order using participles:
Das von mir gegessene Essen war läcker.
The by me eaten food was delicious.
If you’re in the USA, you probably have access to Mango Languages through your local library. I found it to be a great resource for learning Hangul due to the repetition plus the flash cards.
Well, sure, but I’m already studying Hangeul and Korean. I was referring more to people who don’t read Hangeul.
I gave up on powershell long ago when I bumped into an issue where it showed it’s teeth: it was not deterministic. I mean, it worked the microsoft-y way: if there were an edge case, they assumed you want it in a way they decided.
Specific example (memories fading): I wanted to return a list of values inside a list (which has only one member) so it decided I don’t want nested lists and returned only one level deep list.
My takeaway was that when you need some type safety in a dynamically typed language, ps is not for you.
(Pls fix me if I don’t remember correctly)
It’s not a determinism issue, but rather an odd behavior where one-element lists devolve to just the item. So if you really want a one-item list returned, you need to wrap it in a second one-item list. I could get into why it works that way, and I agree it’s stupid, but it’s at least consistent.
I feel like this is something like nushell is also trying to solve. I’ve not daily driven nushell, only experimented with it, and I’ve not touched powershell in some years, so I can’t give a definitive answer on it. Both feel better UX and repeatability from a programmatic standpoint.
ls | where type == "dir" | table
ironically, i think that nushell on *nix systems is a harder sell than powershell on windows because of compat, despite shells being a much larger part of the way people typically work on *nix systems.
i tried using nushell as my daily driver, and pretty frequently ran into scripts that assumed $SHELL
was going to be at least vaguely bash
-compatible. this has been true on most *nix boxes for the past 20+ years and has led to things quietly working that really shouldn’t have been written.
OTOH cmd.exe
is a much smaller part of the windows ecosystem and (at least, it seems to me) there is much less reliance on the “ambient default shell behaves like X”, so switching to the new thing mostly just requires learning.
(i ultimately dropped nushell for other reasons, but this was also over 30 releases ago so its changed a bit since then)
You’ve brought up several valid points, but I want to split this up a bit.
The reason using something other than bash (or something extremely close, like zsh) is painful is due to the number of tools that want to source variables into the environment. This is actually a completely tractable problem, and my default *nix shell (fish) has good tools for working with it. It’s certainly higher friction, but it’s not a big deal; there are tools that will run a bash script and then dump the environment out in fish syntax at the end so you can source it, and that works fine 95% of the time. The remaining 5% of the time almost always has a small fish script to handle the specific use-case. (E.g., for ssh-agent
, there’s https://github.com/danhper/fish-ssh-agent. Hasn’t been updated since 2020, but that’s because it works and is stable; there’s nothing else I could imagine really doing here.) And you could always set whatever shell for interactive-only if you really want it (so that e.g. bash would remain the default $SHELL
).
PowerShell on Windows actually has to do this, too, for what it’s worth. For example, the way you use the Windows SDK is to source a batch file called vcvarsall.bat
(or several very similar variants). If you’re in PowerShell, you have to do the same hoisting trick I outlined above–but again, there are known, good ways to do this in PowerShell, to the point that it’s effectively a non-problem. And PowerShell, like fish, can do this trick on *nix, too.
Where I see Nushell fall down at the moment is three places. First, it’s just really damn slow. For example, sometimes, when I’m updating packages, I see something fly by in brew/scoop/zypper/whatever that I don’t know what it is. 'foo','bar','baz','quux'|%{scoop home $_}
runs all but instantly in PowerShell. [foo bar baz] | each { scoop home $it }
in Nushell can only iterate on about one item a second. But on top of that, Nushell has no job control, so if I want to start Firefox from the command line, I have to open a new tab/tmux window/what-have-you so I don’t lock my window. And third, it’s still churning enough that my scripts regularly break. And there are dozens of things like this.
I really want to like Nushell, and I’m keeping a really close eye on it, but, at the moment, running PowerShell as my daily shell on *nix is entirely doable (even if I don’t normally do it). Nushell…not so much.
You’re absolutely right. It’s a VERY hard sell.
There are all the software problems, some of which you’ve detailed, and then there’s IMO the even bigger problem - the human problem :)
UNIX users don’t just use, love, and build with the “everything is a stream of bytes” philosophy, it almost becomes baked into their DNA.
Have you ever tried to have a discussion about something like object pipelines or even worse yet, something like what AREXX or Apple’s Open Scripting Architecture used to offer to a hardcore UNIX denizen?
99 times out of 100 it REALLY doesn’t go well. There’s no malice involved, but the person on the other end can’t seem to conceptualize the idea that there are other modes with which applications, operating systems and desktops can interact.
As someone whose imagination was kindled very early on with this stuff, I’ve attempted this conversation more times than I care to count and have pretty much given up unless I know that the potential conversation partner has at least had some exposure to other ways of thinking about this.
I’d say it’s kind of sad, but I suspect it’s just the nature of the human condition.
I believe that, in the end, it all boils down to the fact that plain text streams are human readable and universal. You can opt-in to interpreting them as some other kind of a data structure using a specialized tool for that particular format, but you can’t really do it the other way around unless the transmission integrity is perfect and all formats are perfectly backward and forward compatible.
I would argue that scripts that don’t include a shebang at the top of them are more wrong than the shell that doesn’t really know any better what to do with them.
I don’t want to pollute this thread with my love for nushell, but I have high expectations for it, and I’ve previously maintained thousands-of-lines scripts that passed shell-check and were properly string safe. Something I think many people just avoid thinking about. (example, how do you build up an array of args to pass to a command, and then properly string quote them, without hitting the case where you have an empty array and output an empty string that inevitably evokes an error in whatever command you’re calling – in nushell this doesn’t matter, you just call let opts = ["foo", "bar xyz"]; echo $opts
and the right thing happens)
I’ll just leave a small example, so as to not go overboard here. I ought to compile my thoughts more fully, with more examples. But even something like this: https://github.com/colemickens/nixcfg/blob/02c00ef7a3e1e5dd83f84e6d4698cba905894fc7/.github/clean-actions.nu would not exactly be super fun to implement in bash.
I would argue that scripts that don’t include a shebang at the top of them are more wrong than the shell that doesn’t really know any better what to do with them.
Oh, the scripts absolutely are the problem. Unfortunately, that doesn’t mean that they don’t exist. Just another annoying papercut when trying out something new
My experience with FreeBSD defaulting to csh is that scripts aren’t really the problem. Sure, some of them hard-code bash in the wrong location, but most of them are easy to fix. The real problem is one-liners. A lot of things have ‘just run this command in your shell’ and all of those assume at least a POSIX shell and a lot assume a bash-compatible shell. FreeBSD’s /bin/sh has grown a few bash features in recent years to help with this.
FreeBSD’s /bin/sh has grown a few bash features in recent years to help with this.
Oh that’s interesting, didn’t know that but makes sense. I’ve noticed this with busybox ash too – it’s been growing bash features, and now has more than dash, which is a sibling in terms of code lineage.
A related issue is that C’s system() is defined to run /bin/sh. There is no shebang.
If /bin/sh happens to be /bin/bash, then people will start using bash features unconsciously …
Also, system() from C “leaks” into PHP, Python, and pretty much every other language. So now you have more bash leakage …
example, how do you build up an array of args to pass to a command, and then properly string quote them, without hitting the case where you have an empty array
FWIW my blog post is linked in hwayne’s post, and tells you how to do that !!! I didn’t know this before starting to write a bash-compatible shell :)
Thirteen Incorrect Ways and Two Awkward Ways to Use Arrays
You don’t need any quoting, you just have to use an array.
a=( 'with spaces' 'funny $ chars\' )
ls -- "${a[@]}" # every char is preserved; empty array respected
The --
protects against filenames that look like flags.
As mentioned at the end of the post, in YSH/Oil it’s just
ls -- @a
Much easier to remember :)
This has worked for years, but we’re still translating it to C++ and making it fast.
Ah, yes, you certainly know what I (erroneously) was referencing (for others since I mis-explained it: https://stackoverflow.com/questions/31489519/omit-passing-an-empty-quoted-argument). Indeed most times starting with an empty array and building up is both reasonable and more appropriate for what’s being composed/expressed.
I’m very tempted. I tried it out way back when it first came out and checked back in recently on them and it’s amazing at how far the Nushell project has come.
Seems like this change will be reverted soon.
What a trashfire. Also, I am kinda amazed at the number of people who apparently don’t know that Windows has memory-mapped file support–wonder what they’ll think about IO completion ports. :3
I long ago gave up trying to explain to people what Windows can and cannot do. Most devs I run into seem to believe Windows has been stagnant since 1995. It’s really hard to break through that. I’m still showing people basic stuff, like filenames over 255 characters, using volume snapshots to handle backups with open files, etc. To your specific point, I remember being amused when epoll got added to Linux, because some of my friends were like, “see, Linux is gonna be even more better than it already was in the I/O department,” and meanwhile I was sitting there staring at overlapped I/O and being sad Linux was about to reinvent the wheel with zero hindsight.
A statement I like to say is “Windows is the technically superior operating system in almost every way” in part because I genuinely know it to be true, but also because it just provokes the most ridiculous reactions out of people who have no clue what they’re talking about.
“Was that budov
or tudov
?”
“budov
with a ‘B’”
“‘B’ as in ‘Boy’ or ‘T’ as in ‘Tom’?”
“‘B’ as in ‘Boy’”
“This is so much better than numbers.”
“I agree!”
You might be surprised. Your ear focuses overly heavily on vowels, and both “b” and “t” are short-enough sounds your brain will happily confuse the two–especially if you were already expecting to hear one of the two. It’s basically your brain doing error correction–and, like error correction, it sometimes fixes the error in the wrong way. There’s a reason why the NATO alphabet exists, why its letter names are so wildly different from each other, and even why some of the letters or numbers have such odd pronunciations (check out 4 (FOW-er), 3 (TREE), O (OSS-KAH), etc.).
That all said, I’ve never really grokked proquints. As the grandparent is pointing out, they don’t seem to have learned from any of the research that went into the NATO alphabet in the first place. I’m very confident I can read the numbers in the article with fewer errors if both I and the person I’m working with do indeed just stick to NATO phraseology.
Over less-than ideal audio channels—especially if there is no video component—they are easily confused.
The most hilarious thing about Wine these days is that it’s getting so stable, and its support so broad, that it’s becoming one of the most stable and feature-complete GUI toolkits for Linux. I used to feel bad about running my old Windows software on Wine, but the honest truth is it just works–and, since Wine 7 and the redo of Common Controls to support theming, honestly often runs better than e.g. older versions of Gtk on a contemporary system. I’ve wondered, if I wrote brand-new Linux desktop software in 2023, if targeting Wine wouldn’t honestly be one of the best options (even if I wrote “Linux-focused” Wine to just get the benefits of the stable API and so on).
In the same vein, I have encountered some Windows programs that work happily on WINE on macOS but don’t work on modern Windows. I have more chance of running 20-25-year-old software with WINE than with any other toolkit, including the native toolkit for any of the major platforms.
This is amazing progress. This one stood out from the release notes:
Addition and implementation of locale_t and related methods.
I added this to FreeBSD libc ages ago and it’s really important because these are required for a modern (post-c++11) C++ standard library. Great to see.
dl_iterate_phdr implemented.
This is vital for exception handling with shared objects with the Itanium ABI, so I’m not sure how Haiku worked without it, but also great to see.
This is vital for exception handling with shared objects with the Itanium ABI, so I’m not sure how Haiku worked without it
The libgcc
runtime for exception handling does not need it and has alternative mechanisms. But indeed if you want to do your own exception handling it is basically a requirement. This was implemented as part of work to get .NET running on Haiku.
dl_iterate_phdr implemented.
This is vital for exception handling with shared objects with the Itanium ABI, so I’m not sure how Haiku worked without it, but also great to see.
Not running on Itanium probably helped, but it’s also worth noting that, often, Haiku/Be has equivalents for these later Linux APIs, and what’s actually getting added is the compatibility shim. I’m not positive whether this is in that bucket, but I’d be willing to bet on it.
Not running on Itanium probably helped
The Itanium C++ ABI is standard everywhere at this point, including on x86_64, so that’s not really relevant.
but it’s also worth noting that, often, Haiku/Be has equivalents for these later Linux APIs, and what’s actually getting added is the compatibility shim.
Indeed that’s what happened here, our implementation of dl_iterate_phdr
just wraps a somewhat private Haiku-native API for interacting with the runtime ELF loader/linker.
What ever happened to this? I heard a ton about it (particularly in the context of Amigas), and then…nothing.
Here are some details: https://news.ycombinator.com/item?id=9806607
This is a great guide for techy tinkers like us, but if you want something compatible that friends and family can “just use” and send them a single invite link that “just works” I suggest checking out Snikket.
If you have a personal preference for Matrix, it’s a heck of a lot better than many other things you could choose though. Rising tide lifts all boats and all that.
As someone who was involved a lot in XMPP back near the start, most of these points are also downsides:
Time-tested protocol that has demonstrated real-world extensibility to meet the needs of each era as it comes
Unfortunately, the flip side of this is that it’s also prone to fragmentation. The JSF tried to have a reference server[1], but didn’t have a reference client or client library. This led to every client adding features like file transfer and video calling in incompatible ways. This may be better now, but I last tried about five years ago and finding a pair of an iOS and Android client that could do voice calls, send photos, and send rich text messages to each other was hard. And that’s long before you get to things like end-to-end encryption (I think we’re now in the fourth standard for that and, because of the age of the core protocol, it means that you still end up sending a load of metadata in clear text where an intermediate server can record it).
The core protocol was kind-of fine, but then PubSub came along. And then people realised that presence stanzas were a form of pub-sub and that they had all sorts of problems with amplification (presence stanzas are broadcast to everyone. Servers are allowed to drop all except the last one, but a lot of things ended up embedded in presence stanzas and so they got very large). So then personal-eventing over PubSub (PEP) came along and started to move all of these things out of presence. Except that PEP depended on PubSub and none of the servers supported PubSub, so we had years of standards being proposed with no implementations until we were at the point where a client using the modern version of the spec needed to implement 10 different huge XEPs to build the core functionality before it could actually implement any of the ones that exposed this to the user. And none of the servers actually supported any of these. At that point, I stopped paying attention.
Jabber had its chance but managed to completely squander it.
Community-first with development not primarily funded by a single entity
This is what led to the fragmentation in the first place. It’s a community without strong leadership and so everyone implements their own thing. Big companies come along with extensions (e.g. Jingle) and everyone has to jump to implement something compatible because it’s suddenly deployed on a load of devices. Or 5 different XEPs for the same feature, using incompatible mechanisms, end up being proposed and sit as informational XEPs because no one is leading the process of driving consensus towards a single standard.
Lightweight servers and federation that can run on any hardware and over almost any network link
This is true and ejabberd is an impressive engineering achievement. It also supports Matrix now. The clients are a lot more variable .
[1] This was always a bit of a mess. jabberd was fine but then they decided to rewrite it as jabberd2, which broke transports and eventually changed their mind and then decided that ejabberd was the reference implementation (after most people had switched to it anyway), then decided something else was the reference implementation after I stoped paying attention.
It sounds like your main issue is feature fragmentation, something which matrix does not fix (though it’s a bit smaller due to less implementations? But there are still incompatibilities already).
The question I was responding to was specific to my recommendation of Snikket, which is a server+Android app+iOS app and if you use the officially branded apps and server there will of course be no fragmentation.
As a techy tinker I actually quite like the opportunity to try new things, especially when they can be implemented in a backwards compatible way, but agree that for regular users who want “just work” you need a cohesive brand like Snikket.
Well after reading, I am now unclear what’s actually different from XMPP. They even have client compatibility.
Edit: It’s XMPP with guaranteed extensions folded in and an attempt to give those extensions (and some blessed clients) a new name to distinguish it all from the Jabber of old.
This blog runs on Jekyll, one of the original static site generators.
Jekyll came out in 2008. When I was in college in…well, trust me, before that, there were already at least a half dozen generators, all written in Perl, of which MovableType[1] was just the biggest/most popular. (And I think “half a dozen” is probably off by a good order of magnitude.) The rest of the article was solid, but that one line gave me a bit of a spit-take.
[1]: MovableType does generate static HTML; the hosted part just handles the admin interface. That’s part of why MovableType sites used to scale so much better than WordPress. (I am also aware that, somewhere around MT5, they started adding some dynamic bits, but those were actually done by injecting PHP into the static templates, so I’m not sure it counts.)
You’re correct, but Jekyll did kick off a wave of next generation static site generators, and helped popularize the nomenclature “static site generator”.
Personally I used https://en.wikipedia.org/wiki/Greymatter_(software)
I’m running the original (v. 2.1.2).
However, lately I’ve started being disenchanted with the rigid “date & title required” format of most blogging platforms and have started using a “tumblelog” format instead. It’s also bridging the gap between blogging and posting on social media for me, as I repost most entries to Mastodon.
Every time I publish something, I send an update to every subscriber.
Wait, it’s per individual subscriber, not per instance? Why? Am I missing something non-obvious? SMTP can do that.
You can send once to an instance that hosts many of your subscribers. Here’s the relevant section of the spec: https://www.w3.org/TR/activitypub/#shared-inbox-delivery
Thank you! However, just from reading that part it isn’t clear how exactly “receiving server participates in determining targeting”.
If B follows A and then A blocks B, B’s server can still deliver messages from A if A’s server delivers to B’s instance shared inbox. A bad faith instance can evade a block in that sense. Or even in good faith if instance B did not process the block notification somehow.
There are quite a few things that email does better than ActivityPub, and you just hit on a big one. jcs has quite a few above as well, such as the fact that receiving a message from someone you’ve not contacted requires several round-trips between the servers. Quite the additional baggage of a simple EHLO
.
Two bits of prior art:
WMI is something I mention often when talking about administrating Windows boxes with Unix geeks. It is absolutely not perfect, but it made gathering fleet-wide data a breeze. It’s really neat to see that idea translated into the Linux world.
I recently moved into an apartment with symmetrical 1 Gbps fiber internet so acquired an older (but still punchy!) intel NUC off ebay to sit in the fiber closet and host things. It would be fun (?) to host my own mastodon instance, but I wonder whether standing up an instance and federating with others actually makes things worse for those instances, resource-wise, compared to just setting up an account on one of them.
You could also try one of the lighter-weight alternatives. I’ve been running a GotoSocial node out of my home for a few months and it’s only used around 100MB compared to 4GB for Mastodon. Much easier to set up too, since it’s just one self-contained binary.
I’ve been debating doing that, but their docs right now are screaming that they’re only alpha and not to use them. What’s your take been? Not too many bugs?
I’ve got a gotosocial up and the main thing I’ve noticed is that it seems to have weird federation / follow / etc. glitches - probably because whilst ActivityPub is a nominal standard, people seem to have implemented things differently (basically “implement the Mastodon API”). e.g. I can’t find one of my Pleroma accounts from the gotosocial one; the follow I have to a Mastodon server doesn’t show any posts on the gotosocial one. But they’re aware of these issues and seem to be actively working on fixing things.
I have only seen one bug so far, in the rate limiting system. I’m behind two layers of NAT so the client IP address identification is not reliable. Disabling rate limiting didn’t work; I had to raise the limit to 999999 instead. The maintainers have been very responsive so far, so I believe it will be fixed soon.
There are not that many bugs but a lot of missing features. I have a PR open here to make them clearer so people know what they’re getting into: https://github.com/superseriousbusiness/gotosocial/pull/1086
The most annoying is the lack of backfill; sometimes you have to rely on permalinks to read conversations that your server isn’t fully aware of.
Did you evaluate Pleroma as well? I’ve been playing with that in on a free Oracle cloud ARM instance and it seems pretty performant. 1 GB memory total used for entire VM (FreeBSD, Postgres, app). It could certainly run on a RaspberryPi
I used to run Pleroma on my Raspberry Pi (in fact I have implemented new features for it: https://technomancy.us/191) but I can no longer recommend that project due to its association with certain high-profile bigots. I am watching the Akkoma project with interest, which forked the Pleroma codebase and has a more sensible maintainer, but it’s still early days.
run on a RaspberryPi
And there’s PleromaPi for that.
I mean, it can, but federation is also sort of the point of them existing, and owning your own domain is a substantial advantage.
I think all you’d miss out on from a community perspective is you wouldn’t have anyone else in the “local” section, you’d still have the federated section, trending if you enable it and anyone you follow.
I guess I could convince some of my friends to join. Only if I can come up with a good name (I have historically been bad at this).
I don’t think it’s obviously better for the big instance to handle a new local account compared to a new remote instance.
With the remote instance, they only have to send you events once for each activity of some of the people with accounts there. If you start an account there on the other hand, they have to start listening to and storing data from anyone you follow.
I don’t think it’s obviously better for the big instance to handle a new local account compared to a new remote instance.
I don’t think it is but, if I understand the moderation model correctly, it is easier for them to handle a new user on a remote server than a new remote server. In all cases, if the new user is benign then it’s fairly easy. There’s a bit more c2s traffic if the new user is local and s2s if the new user is remote and communicates with local users (follows in either direction, direct messages, and so on). For a malicious user, it’s different:
I don’t know how scalable the server block lists are, but the Mastodon instances that I’ve seen are typically blocking 2-3 servers and list them publicly. If ActivityPub becomes as popular as Twitter, then the easiest thing for a spammer will be creating a new server and then following a load of accounts and then sending them spam. If the only way that this is handled is by every single server needing to manually block the server, then I don’t see any way that this doesn’t turn into a massive problem.
The alternative is generally some form of reputation system. For example, I allow any messages from server A until someone on my server or someone on a server I trust follows someone from A (or until some number of people do). That would work, but provides some friction for new servers: you either know someone who is running one and ask them to trust you at the start, or you need to communicate that you have good people out of band and then have people on other servers follow them. I don’t know if existing Fediverse servers have anything like this.
The alternative is generally some form of reputation system. […] That would work, but provides some friction for new servers: you either know someone who is running one and ask them to trust you at the start, or you need to communicate that you have good people out of band and then have people on other servers follow them.
So basically the same issue as with SMTP servers, then.
following a load of accounts and then sending them spam.
Pleroma, at least, offers you a “following-only” timeline view - a spammer following me couldn’t get any spam in front of me. I could also write a filter which hides/content-warnings posts from previously unseen or “I am not following anyone on” instances using the MRF system.
I don’t know if existing Fediverse servers have anything like this.
I’ve not seen anything regarding “reputation” - but yeah, it would be exceedingly handy to have the ability to assign scores for posts / accounts / instances (+10 for mutual follow, +5 for I am following, -10 for a new instance I am not following anyone on, -100 for “account posts every 5 seconds bloody hell” etc.) much like SMTP spam scores.
Pleroma, at least, offers you a “following-only” timeline view - a spammer following me couldn’t get any spam in front of me
Does that prevent them from being able to send you direct messages? I guess that’s fine for some uses, but it means that people that follow you can’t reach you via the Fediverse.
Done some testing - looks like people you don’t follow can’t send to you, either public or direct posts. Which definitely cuts down on the spam angle. But yes, it does limit interaction from people you don’t follow.
Better check your ISP’s terms of use first. As I heard, a lot of ISP’s deny the use of their service for server hosting and you can end up with your contract broken :(
Yeah I’m on google fiber which as far as I can tell allows hosting for non-business stuff. No static IP though.
GerdaOS was recently unfrozen as a fork for the Nokia 8110 as well.
It would be nice to see more FOSS tinkering in the ‘dumb’ phone space as folks seek to drop their smart phones. I’m not sure what omen IPFS means on Capyloon, but they are running on multiple devices. I wanted FxOS to succeed in the past as I found Java too cumbersome to deal with for Android, and JavaScript + web tech can theoretically all you to right your app once and get a decent enough experience on multiple platforms.
as I found Java too cumbersome to deal with for Android,
The cool thing about Java isn’t the language, it’s the JVM, and there are lots of languages that run on it. These days Android dev seems to be moving toward Kotlin, which looks like a much better language. I’d love to be able to use Kawa Scheme to develop for Android, which should be possible in theory, but …
The dev tooling around Android and Java is another matter. It all seems so very baroque. And getting anything done without an IDE is difficult. I feel like I have to sacrifice seven goats on a night of the full moon just for the equivalent of hello world. Which is why I never went very far with Android development.
The cool thing about my CPU’s ISA is that there are lots of languages that target it. If the first thing that you want to do with a CPU is make it emulate one with a very different abstract machine then something has gone wrong somewhere.
The cool thing about my CPU’s ISA is that there are lots of languages that target it. If the first thing that you want to do with a CPU is make it emulate one with a very different abstract machine then something has gone wrong somewhere.
How’s the language interop with that CPU’s ISA?
If you buy into the JVM, you get a huge standard library of existing Java that is usable from other languages. Then there are the numerous 3rd party libraries. You get some measure of safe interoperability, too. Whereas on Unix, if you want to call something written in another language, you’re going to have to go through C. That necessarily adds unsafe components to an otherwise memory-safe environment.
I’m not trying to sell the JVM, but I do see what makes it attractive as a target.
How’s the language interop with that CPU’s ISA?
All of them?
If you buy into the JVM, you get a huge standard library of existing Java that is usable from other languages. Then there are the numerous 3rd party libraries
Last time I checked, there were over ten billion lines of C/C++ code available in open source repos, but closer to one billion in all of the JVM languages added together. Objective-C had only around three hundred million lines, but could interoperate trivially with all of the C/C++ code.
You get some measure of safe interoperability, too. Whereas on Unix, if you want to call something written in another language, you’re going to have to go through C. That necessarily adds unsafe components to an otherwise memory-safe environment.
Even the preamble to the section on the JNI spec says that it doesn’t even bother trying to validate anything because all bets are off as soon as you call native code, so you get the appearance of safety, not any of the reality. I have implemented a sandboxed version of the JNI, but it requires CHERI hardware and that isn’t exactly mainstream yet.
In 2013 there were a few less options. Eta was cool while it lasted, and I don’t think I’ve heard of any MLs on the platform, like how CLR has F#.
Wait, what happened to Eta?
Kotlin is probably a good enough ML when used in certain strict ways (sealed data classes allow discriminated unions and matching, Arrow can provide useful monads, etc.) that we won’t see something like F#. Honestly, if C# 11 had been C# 2, I don’t know if we’d have F#, either (though I’m very happy we do!).
The Eta compiler hasn’t been touched in years (CLAs don’t usually help either).
I don’t know much about Kotlin, but even if it has ML inspiration, the aesthetics and feel aren’t there (curly blocks, functions need ()
, .
method calls, no first-class pipe/compose operators, sealed class is not the same feel as (G)ADTs). It’d be a hard sell to a lot of folks that it’s good enough.
Reading about these influential systems, I always wonder what they lacked that popular languages had. A marketing department that sold to business needs instead of developers? Random chance? Committed consumers instead of argumentative academics?
Smalltalk and Self both suffered from living in a VM that tried to deny the existence of the outside world. Successful languages benefit from ecosystems in other languages. Swift built on exiting Objective-C libraries, C++ had seamless C interop, C# and VB could import COM components, Python made it easy to wrap C components. The only recent exceptions to this are Java and JavaScript. The latter succeeded by being the only option in its domain. Java is a bit more interesting, since it failed in the Applet space where it was originally pushed but managed to displace COBOL for business-logic programming, largely due to IBM’s backing.
While I agree fully on Self, Smalltalks in the mid-90s that fully integrated with their environment existed and were quite popular. VisualWorks, Smalltalk/X, VisualAge Smalltalk, and even things like Pocket Smalltalk (for Palm OS) all integrated well with their operating systems and did not try to live in their own bubble at all. Most of those products died once Java came on the scene, leaving the FOSS implementations like Squeak (which 100% were antisocial islands), but blaming Smalltalk for being isolationist in the mid-90s when Java came out just isn’t quite right.
I think the secretly big thing about Java is a massive standard library including proper GUI things that … well they look ugly but you could build apps with it. There are so many things people get done in Java with very few-to-no dependencies.
Indeed. It will probably never gain popularity in its true form but I think the “closed off VM” approach is actually really interesting for recreational programming purposes.
WebAssembly is a closed off VM. The host determines which host functions will be available to a WebAssembly module.
Self ran on (expensive, niche) Sun workstations, not ordinary personal computers. I’m guessing that its memory requirements (due to all the JITted code) would have made it infeasible to port in the early 90s, when RAM still cost ~$100/MB and almost no PCs had more than 4MB.
It was not as easy to find out about new and cool programming languages in the late 80s. (source: was alive and programming at the time).
C#/Go relative performance surprises me. I always thought that these are very similar languages in terms of runtime characteristics (value types, gc, AOTish compilation model, user-land concurrency), with C# being significantly more mature.
C#’s throughput for heavy case and memory usage seems worse than Go, which is unexpected — I’d expect C# codegen and gc to be marginally better.
For light case, C# latency percentiles are better, and that’s very surprising as it seems like the case that Go is specifically optimizing for.
What am I missing from my Go/C# model?
Glancing quickly at the code, the C# is very unidiomatic (not surprising, since the author admits they’re new to .NET). A lot of that’s stylistic, but the heavy use of mutable structs with getters, rather than readonly
structs with direct access, is gonna result in some poor cache performance, and may account for a lot of the discrepancy. (I also suspect some alternative data structures would perform better, but I’d need to check first.)
At first glance, I had the same thought. But looking closely, it seems that C# and Go had very similar actual performance and throughput results, with worse outliers for C# (GC related, I would guess).
The weird outliers to me were Swift and Scala, which both seem to get panned quite regularly by people actually trying to use them for the first time. Yet what’s weird (logically irreconcilable) to me is how people who use them all of the time seem to have no major complaints at all.
I always thought that these are very similar languages in terms of runtime characteristics
That seems to be reflected by the data. I didn’t have a look at the code, but concluding from the readme the OP doesn’t seem to have much experience at least with .NET, so the result might rather reflect the level of experience, not the achievable performance. Anyway, even between different versions of the CLR there are significant performance differences (see e.g. https://www.quora.com/Is-the-Mono-CLR-really-slower-than-CoreCLR/answer/Rochus-Keller), and if you add the framework there are even bigger differences.
What am I missing from my Go/C# model?
I think what’s missing is the repo got traction at somewhat of an unfortunate time, with a few optimization tweaks to rust and Go and Elixir, and none yet to C# or Scala. I first posted it here after completing my naive, unidiomatic implementations in every language, but it didn’t take off.
I’d say with that version of the code both dotnet and Go implementations were roughly comparable as was the performance, with dotnet having a slight edge. That’s why I posted on /r/rust asking why dotnet was beating rust.
Following that discussion I made two main changes to the rust which nearly doubled the performance and shot rust to the top: 1) in the response handler, having the TripResponse and ScheduleResponse use a &str
of the underlying Trip and StopTime data, rather than cloning strings, and 2) having the TripResponse vec and nested ScheduleResponse vec initialize with the correct capacity which is known ahead of time, rather than starting empty and growing as I appended new items.
(Oh, and enabling LTO was another boost.)
Since I day-to-day program in Elixir and typescript, it didn’t really occur to me just how impactful initializing the Vec with the full capacity will be, since that’s not even a thing you can do in those languages. After slapping my forehead and seeing its effect on the rust performance, I made the same change to Go, and it shot up some 30% in requests per second.
That’s when the someone else re-posted the repo to HN and it took off.
I expect once I make that same change to C# and re-benchmark, the numbers will be roughly comparable once again. So I think what you’re seeing is the Go and C# implementations have that pretty significant difference right now.
Aha, thanks, this indeed explains the thing!
I’d say with that version of the code both dotnet and Go implementations were roughly comparable as was the performance, with dotnet having a slight edge
Is what I’d expect, and looks like that exactly what happened here! That’s very interesting data-point, for “time-to-performance”
My guess is that C#, being object oriented, likes to use references when not necessary, which has a significant effect on time and memory usage.
Both Go and C# have value types, which are not address-taken and so don’t incur any penalty for GC but do incur some overhead from copying. Performance in both languages can vary significantly depending on the degree to which you make use of these.
Good for them, but this is like… the exact opposite of what I want. XD
And I’m not expert but considering that margins are low and competition is high at the low-end, this seems like a poor strategic move. Hopefully Google is paying them well for it.
This is like making a ceramic Solo cup. Who wants a high-end Chromebook? Who wants a Chromebook that can be serviced easily? The whole point of Chromebooks is that they are disposable and have no local state.
I imagine there are people who like Chromebooks and do not think computers should be treated as disposable. I don’t know that there are many, but that’s because I don’t get Chromebooks.
I think it’s not about” disposable”, it’s about “replaceable”. I had one of the first Chromebooks and for non-dev work I loved it. I could use all my favourite websites, read all the articles, do most of the stuff I do on a computer when I’m not working. And when coupled with the (then unofficial) SSH extension, i could even do some light work in vim. Not real dev work, but some tests and trying things out and fiddle with the servers.
Think of it as an advanced tablet. It’s not useless, but it’s not usable for everything, at least not as a primary computing device. I almost never had a tablet, but i liked my Chromebook.
And as such, why not aim for high quality product and high end market? People but iPads and surfaces and I never would, and I don’t think ms or apple or their customers are stupid.
The whole point of Chromebooks is that they are disposable and have no local state.
That was certainly the original sales pitch, but there’s a concerted effort away from that in the past few years. The new pitch is that Chromebooks allow you to give an always-up-to-date, easy-to-lock-down tool to everyone in your company/school that, when damaged, loses no data. Throw in their ability to run Wayland and Linux, and I’ve seen a couple of full-on web dev companies that give all their employees powerful Chromebooks, rather than MacBooks.
Do I want that? Hell no. But But apparently some people do—and since “some people” seems to overwhelmingly be large school districts and massive companies, there is money to be had there.
I’m not seeing those types of places wanting to buy a trivially hackable laptop, though…
I’m also baffled by this. Who are these people that will pay a premium for full control over their hardware but don’t care at all about controlling their software?
I would not classify the Framework laptop as “Free Hardware,” but would say that some people want to be able to lifecycle their machines forever, no matter the OS. I further doubt it would be hard to install Linux on the mainboards on these Frameworks.
Putting on my tinfoil hat, this was a part of the long-term bet of Google getting Chromebooks into the education system. Now with children growing up and indoctrinated into the Google ecosystem, they’ll find this just a hardware transition lessoning the burden of a software transition too—especially with all their data in the cloud. This is probably why I see a lot of younger folks here just using iPads and aren’t sure how to handle when there isn’t an app for that (sent an AsciiDoc file and there was no way to ‘open’ it).
This is another reason why FxOS was too ahead of its time. Boot2Gecko being in the hands of children would make me feel a lot safer than its Google alternative.
What a crappy writeup… the amount of time given to fossil does it no justice. I’ve been using it locally for a few months now and hosting multiple repos and I’ve had such a good experience. So easy to run from a jail on my TrueNAS and even add offsite backups to because all the projects sit in the same directory with a single file each. For open source I think you could easily do some sort of “fossil localdev to public git” flow. The focus on windows/WSL is also annoying but I suppose it allows the whole post to be dismissed for folks who use neither. Hopefully the mention of all the different projects sparks folks’ interest. I think it’s fun to tinker with using different VCS tools.
The focus on windows/WSL is also annoying but I suppose it allows the whole post to be dismissed for folks who use neither.
Windows compatibility is really interesting: it’s important for a lot of users but not something a lot of developers have the computers, interest, or even awareness to match. Anything that wants to seriously compete with git would need to run natively on windows without wsl.
But Fossil does (it’s a single drop-in executable via either winget
or scoop
), and Git not only runs fine on Windows; it’s the default SCM that Microsoft internally uses these days. This would be like evaluating Subversion on Linux by running TortoiseSVN on WINE.
Git runs on Windows but it’s not “fine” - it’s painfully slow and a little finicky to setup.
Personally it doesn’t bother me enough to run through WSL, but I’ve heard people suggest it.
It’s slow enough that for big operations I’ll occasionally switch over to the shell and manually run git commands instead of using Magit, because Magit will often run multiple git commands to get all of the information it needs, and it just slows down too much.
Context for this response: I did Windows dev professionally from 2005 to 2014, and as a hobbyist since then. Half the professional time was on an SCM that supported both Mercurial and Git on Windows.
Git runs on Windows but it’s not “fine” - it’s painfully slow and a little finicky to setup.
Setup is literally winget git
(or scoop git
, if you’re weird like me), aaaand you’re done–or at least in the same git config --global
hell everyone on Linux is in. Performance has been solid for roughly four years if you’re on an up-to-date Git. It’s not up to Linux standards, because Git relies on certain key aspects of Unix file and directory semantics, but there are even official Microsoft tools to handle that (largely through the Windows equivalent of FUSE).
Running anything through WSL on files will perform atrociously: WSL1 is slower than native, but mostly okay, but WSL2 is running on p9, so you’re doing loopback network requests for any file ops. I do run Git in WSL2, but only when working on Linux software, where it’s running natively on Btrfs. You’re trying to lick a live propeller if you use WSL2 Git on Windows files.
I have zero experience with magit on Windows because Emacs on Windows is, in my opinion, way too painful to deal with. I love Emacs on *nix systems! Keep it! It’s awesome! This is just about Windows. And in that context, things like e.g. Emacs assuming it’s cheap to fork a new process–which it is on Linux, but not on Windows–can make a lot of Emacs stuff slow that doesn’t need to be. That said: if you’re using native Git, and not e.g. Cygwin or WSL1 Git, it should perform well out-of-the-box.
To clarify, most of the finicky setup on Windows was related to SSH keys, because Windows doesn’t support SSH well. Eventually I ended up getting it working with Putty, IIRC.
I have the opposite experience with Emacs on Windows. It more or less “just works” for me, and it’s really the only way I can tolerate using Windows for development. Somethings are slower (basically anything that uses a lot fork/exec, like find-grep), but for the most part it’s the same as on Linux and OSX, but a version or two behind :-/
I suspect we just have different expectations as far as Git performance, though. I’m using the latest version (as of a couple months ago) from https://gitforwindows.org/, have “core.fscache” turned on, and other “tricks” I found via StackOverflow (a lot of people think it’s slow on Windows) to speed things up, and it’s still noticeably slower than on Linux - especially for large commits with big diffs.
As a reminder, this article was about Git versus other SCMs. That said:
To clarify, most of the finicky setup on Windows was related to SSH keys, because Windows doesn’t support SSH well
SSH and ssh-agent
are built in since at least Windows 10. It’s directly from Microsoft, requires no third-party dependencies, and integrates directly with the Windows crypt store and Windows Services manager.
I suspect we just have different expectations as far as Git performance, though
Git on Windows does perform meaningfully worse than on Linux. Two reasons are generic (sort of) to Windows, one to Git. On the Windows front: the virus scanner (Windows defender) slows things down by a factor of 4- to 10x, so I would disable it on your source directories; and second, NTFS stores the file list directly in the directory files. This hurts any SCM-style edit operation, but it’s particularly bad with Git, which assumes it’s cheap. That last one is the one that’s partially Git-specific.
In the context of this article, though, Git should be performing on par with the other SCMs for local ops. That’s a separate issue from the (legitimate!) issues Git has on Windows.
SSH and ssh-agent are built in since at least Windows 10.
That’s a tiny bit misleading. Windows 10 now includes them but it certainly did not include them when it shipped in 2015.
Eh, that’s fair; Microsoft’s decision to call over half a decade of Windows updates “Windows 10” leads to a lot of confusion. But in this case, the SSH bits I’m talking about were added in 2018—five years ago. That’s before React Hooks were public, or three Ubuntu LTS versions ago, if you want a fencepost.
That’s definitely a bit older than I thought. If I had to answer when it shipped in mainstream builds without looking it up, I’d have said it was a 20H1 feature. At any rate, I wasn’t calling it new so much as saying that “at least Windows 10” reads as “2015” to me.
I have the opposite experience with Emacs on Windows. It more or less “just works” for me, and it’s really the only way I can tolerate using Windows for development. Somethings are slower (basically anything that uses a lot fork/exec, like find-grep), but for the most part it’s the same as on Linux and OSX, but a version or two behind :-/
Same. Emacs on Windows is good. I use it for most of my C# development. If you want to not be a version or two behind, let me point out these unofficial trunk builds: https://github.com/kiennq/emacs-build/releases
Git runs on Windows but it’s not “fine” - it’s painfully slow and a little finicky to setup.
I’d say that setup is not finicky if you use the official installer — these days it sets up the options you absolutely need. It’s still painfully slow, though, even with the recently-ish-improved file watcher. It’s generally OK using from the command line, but it’s not fast enough to make magit pleasant, and it’s slow to have git status in your PowerShell prompt.
thanks for pointing out the package managers for windows. I saw brew
is supposed to work as well but have no context other than a cursory search.
Yes, it was built in a startup in the city I live. It’s probably the best VCS out there if you’re a GUI person or work with big binary files, however, the setup was a bit complicated at the time (it is both distributed and centralized VCS, but to accomplish that, you should run several components at the same time). They’re now focused on videogames use cases and never wanted to replicate the famous free and social aspects of GitHub or GitLab on their hosted services.
Perforce has also been relegated to the gamedev niche too. Surprised it’s big enough for multiple players, and that LFS hasn’t eaten it yet.
LFS (and Mercurial’s equivalent) are painful compared to Perforce, Plastic, or even Subversion: the gap between what’s in the repository, and what the repository means, is a problem unique to that style of “fix”. Narrow and shallow cloning combined get pretty close to matching the quality of Plastic/Perforce/Subversion/etc., but it’s still half-baked when present in the FOSS DVCSes.
C… can you do with with German too? I’m a little scared of the answer…
My father once told me there’s a German joke about an elderly professor who delivers a lecture that’s all one very long, dense, digressive sentence … and he spends the last five minutes rattling off all the verbs.
I’ve heard it phrased similarly to:
“What’re you reading?”
“An essay on […] by a German philosopher.”
“Oh, is it interesting?”
“I don’t know yet, I haven’t gotten to the verbs”
ChatGPT tells me these are called “Schachtelsatz” or “nested sentences,” though unfortunately it can’t reproduce the exact joke.
German isn’t concatenative like this. While verbs do go at the end in certain subordinate clauses and when using compound verbs (“I have the beautiful red apple eaten, that I yesterday at the neighborhood supermarket bought. It tasted great!”), you’ll notice the overall sentence structure is not doing the same stack-like thing Korean does. Japanese would definitely fit the bill, and highly agglutinative languages like Finnish and Turkish you could probably shoehorn in there (they at least have an OO-style builder pattern happening), but I don’t think German would be a good match.
On the flip side, Biblical Hebrew and Classical/Modern Standard Arabic are great examples of prefix languages, but I probably wouldn’t call either a Lisp.
Isn’t it true that VSO languages like Biblical Hebrew and Welsh typically switch to SVO in subordinate clauses or when certain other grammatical things happen, like verbal auxiliaries? I think this speaks to your point if my recollection is right.
I can’t speak generically to VSO languages, but in Hebrew, yes, subordinate clauses are effectively SVO. Note, though, that Biblical Hebrew, and I believe Classical Arabic, aren’t really VSO as much as V…and then everything else in an order that conveys what the speaker wants. “Looked to the sea, he did”-type word orders, for example (without the trailing auxiliary).
Funny, Spanish is like this too. It’s usually SVO, but you can rearrange to put emphasis or for poetic effect. E. g. you can say:
• “Juan corre la maratón” (SVO; neutral statement, but also could be used to negate that Juan runs some other race)
• “La maratón la corre Juan’ (OVS; used to negate that some other person runs the marathon)
• “La maratón Juan la corre” (OSV; negates that Juan does something else with regards to the marathon, e. g. watch it on TV or something)
“Juan la maratón la corre” (SOV; pretty much equivalent to OSV)
• “Corre la maratón Juan” (VOS; again the emphasis is on the subject, mostly used when the subject is compound, like a list of people)
• “Corre Juan la maratón” (VSO; like OVS, somewhat weirder-sounding though)
Turkish is similar: whatever comes before the verb is emphasized.
Sentences which don’t have the verb at the end are rare in formal speech and writing, however. They’re referred to as “knocked-over sentences” (devrik cümle), though not seen as “incorrect”.
On the topic of word order, I highly recommend this video: NativLang, “OSV: Why is this word order so rare in languages?” https://www.youtube.com/watch?v=6YIz1HXDbCI
Yeah you’re right, I didn’t think too hard about the concatenative aspects.
In penance, I offer some sci-fi worldbuilding about an alien language that is explicitly stack-based: https://well-of-souls.com/outsider/umiak_language.html
Korean is probably, like Japanese, a strongly head-final language. English is a head-initial language. German, however, may be fairly called a “mixed” language; there is, to the best of my knowledge, still some controversy over what the underlying head directionality parameter is; and phrases demonstrating both directionality are common in German. As others have mentioned, the verb in German comes at the 2nd position in a phrase, except when it comes at the end, &c.
This means that the same kind of consistent stacking structure isn’t available.
The “head” of a phrase is the word that gives a phrase its grammatical function – the word with the same part of speech that the overall phrase has. Some discussion of head directionality, and of how it differs between English and Korean, can be found in “The Resetting of the Head Direction Parameter” (2015). One early passage notes:
Among those who posit head directionality parameters, I believe the consensus is German and Dutch do have a head-final verb phrase.
The reason why, despite this, the finite verb of main clauses is in the second position is another parameter, the V2 parameter, which all Germanic languages except English have, and which says that the verb must move to the so-called C position, which happens to be in the second position in the word order.
In subordinate clauses, this movement is blocked because the C position is already taken up by the complememtizer (e.g. das, ob, als).
German would be like Haskell/PureScript languages with type classes because all words are a semigroup and can be concatenated together to form bigger words.