My last post accused Python of being The Slow of the Internet, not because Python is bad but because bad Python is awful.
In many cases, Python is really not slow for the reasons you think it is
Python is a great glue language, a terrific scripting language, because it provides fantastic facilities for manipulating bulky amounts of data. The terrible language that makes our day-to-day lives slower and more miserable is actually anti-Python.
There are two sides to the Python problem: non-engineers using it to write runtime descriptions of data manipulations performed by non-python backends, and engineers writing it as an expose of their non-python backends.
Between the two groups, nobody is really here for Python.
Unpopular Opinion: CPython is stupidly slow. CPython is the Python you’re using if you don’t know which Python you use.
Before Go, Python had taken a firm hold of the systems admin coding, and huge amounts of Linux tooling is written in Python.
During the Great Python 3 Migration of 2019, Python libraries bloated with people introducing bidirectional compatibility, generally by just grabbing some 3rd-party libraries to minimize the footprint of change.
I’m not going to rant about people not knowing the standard ‘dis‘ module exists, or they don’t know about timeit/%timeit… It’s not really an “optimization” issue tho.
Today’s Linux admin activities are agonizingly slow because so many Python developers hear adages about not optimizing Python code they think that you never need to worry about it, so they have no idea how expensive some very common practices are.
Sadly, CPython makes no-need-for-performance-thinking untrue in one really unfortunate detail, one detail that has been agonizingly inflated by the bloat of compatibility code:
I’ve mucked about trying to resurrect AMUL here and there over the years, reworked a bunch of it under the moniker “SMUGL” but once I was done with the particular aspect (sockets, classes, whatever) I never got to the important task of making it work.
After another couple of forays into poking the bear recently I tasked myself with strictly focusing on finding what was making it crash and fail to load.
It turned out that some time in probably 97-98 I’d deleted a line of code necessary for the game to figure out how much data it was loading, oops.
Largely it turned out to be my lack of C++ understanding in ’92. Apparently I learned the lesson but decide not to apply the learnings.
I’ve tried to mostly stick to pretty much C code, but then luxuriated in a few “really does something useful” C++ features to let me focus on the important and fun parts. I’m going to try and keep the struct/class hierarchies flat, with a very limited amount of inheritance to fill in for the absence of interfaces in C++.
It consists of three main components:
Compiler: Which is a bit generous of a name for what it really does, in my mind anyway. It consumes various text files and spits out a set of binary data files.
Engine: AMUL had a server (manager) and copies of the “frame” (a combination client/server) directly manipulated its memory. SMUGL has a single executable which simply forks itself to become a client. Static data is visible to the child and shared memory homes the mutually-modifiable data.
Game code: Someone actually has to describe the game world, commands and behaviors.
The language itself is part data definition and part functional programming, in that you are writing pattern matching sequences followed by lists of steps to execute when those patterns are matched.
verb=help # How to deal with a player input starting with help
syntax=player=me # more specific: "help me"
respond "I'm just the narrator, ask another player?"
checknear player # make sure we're near the player you named
if helping player fail "You're already helping them."
if helping someone fail "You're already helping @hp"
help player # execute the built-in 'help' action
tell player "@me is now helping you."
respond "You are now helping @pl."
fail "I don't think it can be done."
respond "That's not how this works, you tell *me* what *you* want to do."
The current language is overlyspecialized, but on a modern system I think I can quite comfortably address some of the issues that effectively forced my hand back in the day.
I’ll probably spend the next few days of hacking replacing the “Posix Shared Memory” code with memory-map backed storage so I can run it on Windows, and doing a better job of separating dynamic from static data. Then I’ll whittle down some of the “muscle work” code that I feel comfortable entrusting to the C++ standard library/my own simple classes/templates.
My big plans are for completely replacing the compiler’s parser and parser generators: I’ve fleshed out a design that intentionally falls short of being a complete parser generator but instead meets you half-way with a fairly clean and readable actual-code description of your language as a state machine.
// names starting lower-case are user-written functions that capture
// token(s) and validate them.
error_t newRoom(Token); // write a function to capture a new room name
error_t addRoomFlag(Token); // write a function to capture/check each flag
auto RoomLine = Optional("room=") + (Identifier()->newRoom) +
auto RoomShortDescription = LineOfText()->shortDescription;
auto RoomLongDescription = ZeroPlus(LineOfText())->longDescription;
auto RoomParser = RoomLine() + RoomShortDescription() + RoomLongDescription();
Lastly I want to abandon the current fork-per-client model. I’ve written a small replacement library that emulates a portion of the Amiga’s “Message Ports” message-passing system. By using that and “thread_local” on my excessive number of globals, I think I can quickly get to a working single-process, multi-threaded version (and then get rid of all the globals)
I’m trying to work up to opening up the source repos, but I’m not quite ready to do it.
The foray into raw C has been fun, but there are three things that I miss: references from C++, multiple-return types from Go et al, and some variation of function-to-structure association.
References save a lot of null checking, and ‘.’ is two less keypresses than ‘->’.
Multiple return types lets you tackle the oddity of “pass me the address of the thing I’m going to give you”
// what I mean:
read(char* into, size_t limit) returns (bool success, size_t bytesRead)
// what c libraries do:
ssize_t /* -1=err */ read(char *into, size_t limit)
// what I do:
error_t read(char *into, size_t limit, size_t *bytesReadp)
But that pointer on the right means an input parameter to my function instead of the output I want to denote.
Methods give you name spacing, first and foremost, but they also just provide a logical separation I find I’ve missed in going back to C.
In particular, Go’s method implementation really appeals to me.
Go doesn’t have the complication of header files, so unlike the C+… family of languages, you aren’t bogged down with boiler-plate and it also didn’t feel the need to convolute structure definitions with pre-declarations of implementations of functions.
When viewed thru a C++, Java, C# etc lense, the following will make your skin crawl:
On the left, (b *Buffer) is the “receiver” type, it’s how Read is associated with Buffer. On the right are the parameters, into, and after that is a list of the return values.
How are you supposed to know what methods a class has? That’s probably part of what made your skin itch.
The answer is: Probably not by going and reading header files or code. Go has incredibly powerful tooling that makes it a doozie to integrate with IDEs and editors. It’s sickeningly fast to parse, and documentation is generally highly accessible.
I’ve about gotten the AMUL code to a place where I’m ready to think about trying language only C++ – that is, C++ language features but none of the STL.
Ordinarily, at this point, I would be sharing my github repos so you can see the code I’m tinkering with. Two things are stopping me.
The last time I shared the code for AMUL, it was with someone I was discussing a possible port to Linux with back in ’94. That someone said “Can’t help you” and I got distracted with my job at Demon Internet. A few years later I found that a lot of concepts from AMUL had surfaced in another MUD language across the 6 months immediately after sharing the source, and that the individual I’d shared it with happened to be the author of said language…
More importantly, my snapshot is not of the last release. I don’t know why that bothers me (re sharing), except that I’m hoping I’ll find a more recent version that has the huge swath of cool stuff I introduced between the version I have code for and the AMUL900 that’s still out there. I think it’s knowing that I have probably lost the files at some point, or they are buried so deep in my nested collection of archives that I’m not finding them :)
Meanwhile, I’m still really super-enjoying working in pure C on this project. I wouldn’t necessarily choose it for a follow-up project, but I’m spending radically less time on boiler plate.
I spent a part of today formalizing bits of stuff I had in external folders – so now there’s a Dockerfile for an ubuntu and an alpine build environment.
One advantage of doing this in C, at least first, is that it’s proving a lot easier to static analyze and bug hunt.
Saw a cool-looking desk lamp at Best Buy the other day and made the mistake of letting the Dyson vendor start talking to me about it.
It’s a work light.
That costs $599.
Because (a) the arm conducts heat away from the leds, you know how leds are infamous for burning out because of heat, right, well thanks to the arm these can last YEARS until you have to replace the entire unit because it’s special magic LEDthat will cost you more replace than a new worklight! (b) it has super-high-tech secret sensors that allow it to match the ambient light.
Or: It costs $599 because it has a special LED, designed to get really super hot, attached to a heat-conducting metal arm with a heat-pipe in it that will conduct that heat straight into your hand when you try and adjust the lamp – which you will do regularly because you can’t tell whether the light is on or not.
Frankly “can’t tell whether the light is on or not” is the opposite of what I look for in a lighting solution. And when the guy demod it for me, it really did match the ambient light so well that we both had to tilt our heads to look directly at the bulb to be able to tell it was on.
The guy took great pleasure in showing me how you could raise or lower the arm, how it rotated, and then nearly flipped out when I started to reach for it.. Not only can you not tell whether the light is on or not, you can’t point it where you want, and people keep breaking his floor models by trying to twist or pivot it. The mechanism on the stand looks exactly like the kind of mechanism that would allow you to tilt or twist the arm. The picture on the front of the box is even taken from a bizarre angle that makes it look like the lamp has had the head tilted upwards.
But it was standing in-front of images like these:
And what I refer to as the “light comes out here” picture
But I think this actual Dyson promo picture sums it up
Yep – if there’s one thing you want from a work-lamp, other than light, having it directly overhead of what you want to work on, right at eye level, that’s got to be right up there… I’d throw my money at the screen but it’s too dark in here to see my money or the screen…
A about a month ago, I dug up an old copy of my MUD language from 1990, and took a crack at refactoring some of it in C++, but I quickly got frustrated with just how much that felt like work rather than fun, especially after my recent foray into golang.
So I have this 29+ year old code, written in original K&R ANSI C, and I want to get it, say, at least compiling.
Cambridge Analytica weren’t doing rocket science or hacking. They didn’t get your social security number, your phone number or your browser history.
They built a few ad-targetting criteria with such low precision and accuracy any marketing person would be ashamed of the numbers.
That imprecision played to their ends. Remember the goal was to be disruptive, so although they were using ad-targetting technology, having built-in misses was actually a boon.
What they did was:
1. Get people to fill out a survey,
2. Collected their facebook profile data with consent,
3. Collected uninteresting public profile data about their friends like public group memberships,
Then they used some machine learning systems to:
a- Build an ad-targeting profile of the survey respondents using #1,
b- Build the same ad-targeting profile using #2, but “back-train” it by correlating #1 and (a),
c- Use (b) on that uninteresting public stuff in #3.
They weren’t trying to pin down anyones’ precise political alignment or belief system, they were looking for broad strokes: Watches Colbert, Watches Hannity; Loves Guns, Loathes Guns.
There are a couple of RTS type games for VR, but they’re just projections of the existing style of game, and doing this stuff by hand is clunky and annoying.
What I’d like to see is a VR-capable building game that lets you operate from the old top-down perspective for viewing the big picture, but lets you zoom on down to the in-situ level to see what the people are doing and to do things like plan/upgrade buildings, and using gestures etc to give it a cyberspace-god-like feel.
Figure: You’re standing on the gravel path watching your woodworkers heading out to chop down trees. They mumble about being hungry as they pass. Oh yeah, I could use a bakery. Circle your hand to open the blue-glowing buildings rolodex, tap your hand on the glowing bakery image, and then throw it down to roughly where you want it; use both hands to twist/position it, and then bang your fist down to make it so.
You could, of course, do all of this from the more conventional menu systems, but including the creators-eye view would just make it that much more kick ass :)