5 ms·
I love seeing projects like this! I have one too, but it completely throws away compatibility and is very simplistic. I opted for a lisp-like language instead o
by skulk 3y ago
I love seeing projects like this! I have one too, but it completely throws away compatibility and is very simplistic. I opted for a lisp-like language instead of a lua-like language (https://github.com/sid-code/nmoo https://github.com/sid-code/nmoo but don't look at the code, it's embarrassing).
I have some questions:
- Does each verb call create a whole new world state that it mutates, and later commits to the database? That's the impression I get from reading the code. Does this come with a lot of overhead?
- What is that emacs mode you're using to edit verb code?
- cmrdporcupine 3y agoI've done the "whole new thing" before, too. 20ish years ago, tho I only have a few fragments of what I worked on back then: https://github.com/rdaum/mica https://github.com/rdaum/mica being one of them I found on an old drive. Not complete. But sticking with compatibility has allowed me to enforce development discipline, basically. And then I'll move it onwards from there. I have many ideas. And a product concept (if I could find an investor...). But I felt it important to start with a thing with existing foundation and use cases before doing the exciting stuff/changes. Re: world state / transactions -- yeah, basically all I/O and mutations happen in a transactional context, and then at commit time conflicts are resolved; if they're not resolve-able, the transaction is retried in a new state. As for overhead, yes potentially maybe a lot, but it's also a solvable problem; this is how an MVCC SQL database (like, even Postgres) works. TLDR it's likely inefficient now, but I believe I can make it efficient. And I think it's the best way to solve the shared world state problem and still meet user's expectations of consistency. Original LambdaMOO had a global interpreter lock and only one user was mutating the world at a time, in their given tick slice. Not gonna scale. Re: the MOO client, it's `rmoo.el`: https://github.com/lisdude/rmoo https://github.com/lisdude/rmoo -- it's been around for a long time (25, 30 years?) and it and/or MOO.el (another emacs one) are how/why I learned emacs in the first place. I had to minor patch my local copy to make it work with emacs 29.1, though I don't know elisp well enough to say whether my patch is the right thing to do or not, so... EDIT: I just re-read and saw you asked whether each new verb call creates a new state, and actually it's not that. It's each new command or network transaction, which can in fact lead to a chain of verb (method) calls. Recall a MUD has a command loop, so basically a transaction begins at command entry, and commits when all the invoked methods/verbs provoked from that complete.
- derefr 3y ago> Original LambdaMOO had a global interpreter lock and only one user was mutating the world at a time, in their given tick slice. Not gonna scale. I’ve previously seen (abandoned) attempts to convert the Erlang runtime directly into a MOO runtime. Each command being a concurrent actor-process would make a lot of sense to me. (Though a semantics where all commands are MVCC against the at-inception world-state and will rollback or retry on conflict, kind of moots having any kind the advantage of a runtime based on message-passing, since you’re not going to be passing messages between separate concurrent “sessions.”)
- cmrdporcupine 3y agoYeah the whole actor thing is kind of orthogonal to the question of how you handle the shared world state (which is what makes a MOO a MOO.) There are parts of my runtime that look Erlang-ish, Actor-ish, because that's a concurrency pattern that Rust does well with, in general. In the end a MOO is just a database with fancy stored procedures. And the original code is not a particular... good one. Handling serialization conflicts is what databases have to do as one of their core abilities, and LambdaMOO just tries to punt on the whole question.
- smirya0 3y agohow did you come to pick Rust (just curious, vs Elixir, Java with Loom, etc)?
- cmrdporcupine 3y agoThese days Rust is both my day job language (I work on systems for autonomy in tractors) and my hobby language. It's my preferred tool. I have attempted similar systems in C++ before, and got fairly far along at times. But Rust really solves a lot of problems, I tear my hear out a lot less. This is a "systems" type of application; this is a database and compiler and a virtual machine and language runtime. I'm not super concerned with optimization at this point, but I will likely have to be at some point. Being closer to the metal is key for me on a project like this. I'm likely to e.g. rip out RocksDB and replace it with my own database engine at some point (something I work on here and there as another side project, unpublished still.) I will also likely need a better garbage collection solution. With Rust I have options. The community of libraries available for Rust is good. The right tools are there. And the language is expressive enough to make it work well. That said, I have mulled writing the "host" portion -- the layer that manages network sockets and web endpoints, in Elixir/Erlang: The 'daemon' portion of the system sits behind an RPC layer built around ZeroMQ -- so that layer can be restarted/upgraded without losing active network connections. Or can sit on a separate machine for scalability reasons, etc. So it's entirely possible to split what I'm calling the "host" (network facing layer, what we used to call a "frontend" when I worked at Google, but most people think of that term as referring to a UI layer) from the backend "daemon." Anyways for me this project ties together a bunch of interests in systems programming I've had for years. It becomes a kind of synthesis project.