106 karma · joined January 27, 2023
In a true meritocracy everyone must have the same starting point and rise up within the ranks based on their merits from there. In our society we do not all start at the same place. There are people born into wealth and people born into poverty. So some people have to struggle harder to get to the same place as others where born into. Essentially an anti-meritocracy system.
If anything UBIs will help make the system more meritocratic since the ones the bottom no longer need to climb the first hill.
I mean I enjoy my work, for the most part anyway. But if I could spend all my time with my family and hobbies I see that as an improvement rather then something to be depressed about.
Making sure that everyone understands how to use your part (and that the overall architecture is at least coherent), in a big project, is actually more important than if that part is of high quality. And since communication is more important it's the seniors responsibility.
Sometimes I really want to go back to the junior years it was in general more fun back then. But getting to decide the architecture does have its charms.
When a feature is implemented I preferably want the entire thing before me when reviewing. Otherwise I find it hard to keep track of everything that has happened.
Not to mention that the small focused changes might be reviewed by different people leaving only the implementer in full knowledge of everything that was done.
Peer/Assembly programming help but if you do peer/assembly programming reviews are mostly a waste of time (especially for assembly programming).
So when reviewing my carelevel is highly dependent on if shared code is touched. If the commit only contains changes in the leafs eg subclass / single microservice my gut instinct is to trust the code and go into LGTM mode (if it goes wrong it's at least localized). But if shared code is touched I don't trust it, I deep dive and complain about everything I can think of.
But in a dynamic language like python your options are limited.
Consider:
def add(a: int, b: int) -> int: return a + b
assert add(1,2) == 3
a, b = random.choice((3, 4), ("foo", "bar"))
assert add(a,b) in (7, "foobar")
In the first call we use ints and are golden. In the second we get ints or strings and we cannot know which until runtime.
So if we are going to use type information for speed improvements how should we proceed?
Some ideas.
1. Generate special purpose small (32 or 64 bit) integer version in a custom type aware bytecode format or ASM and a common version of the function. Use run-time typechecks to decide which one to use.
We generate two versions of the bytecode instead of one we also run some optimizations on the integer version to actually get a speedup when we call it.
To do the integer optimization we probably need a new special type aware bytecode format. (or just compile to assembly directly) To get advantage over the interpretor where everything including integers are objects.
When we call 'add' we just check the type send the values to our new bytecode format and bam faster add (possibly faster anyways).
Having two versions of the function will take extra memory and increase startup latency (during compilation to bytecode)
In some cases we could directly call the integer version of add like in the first call we know we are working with ints, in the second call we cannot know until the type check if we are dealing with ints or strings.
Will all of this be worth it? We use extra memory, slower startup time and an extra typcheck when we are not 100% clear on the types.
For hot code it could be worth but we do not know what code is hot and what is cold until we run the program. We could tell the compiler what is hot and what's not like 'numba' does, but then we are going beyond typing.
So why does python not so this? Well for a start it's very unclear that we will gain performance from this extra compilation / bytecode swapping but it will slow down startup. It will also be a massive change to the internals of the standard interpretor and need tons on man hours supporting this beast.
At a first glance it does not look that hard to do this extra compilation but the add function is very simple. What about more complex code that calls unknown methods that have not been defined yet possibly even loaded at very late at runtime. Will the ASM layer help or hinder when you need to go back and forth between the interpretor and optimized code? The interpretor really does not have enough information to make intelligent decision on this.
2. We could go the route of static languages. Compile only a special case integer version.
Assuming that we always use the function correctly this could be fast.
But this would be extremely unsafe in a dynamic language, if we don't have an integer but do integer additions on the objects internals anything could happenn.
Now if you have full static typing you can do this, really you should do exactly this. It is safe to assume that we are calling the function with the correct types, since it's enforced at the language level. Which leads us to do all kinds of optimizations that the dynamic nature of python prevents.
3. Just use a JIT like 'pypy'.
A JIT would do basically option 1 but only after hot code paths have been identified. Startup time is less of an issue since we delay compilation untill we are sure we need it (or fairly sure at least).
Type hinting could help guide the JIT if you using fairly specific types such as 'int32' instead of int to highlight that we are just interested in small numbers. But the information might also be missleading so it might opt out of using it altogether.
-------------------------------
Cpython does not do (1) since its not clear that you get any substantial speedup and startup latency is a big deal. Does not do (2) since its super unsafe. And it's not a JIT (3).
Trying stuff over and over again in different variations using maybe different languages, dealing with all the errors the frustration and overcoming them.
I think that using chat gpt or similar llms to learn how to code is similar to using Midjorney to learn how to draw.
Don't get me wrong you might be able to produce results fast but taking shortcuts is not going to speed up understanding.
You can still have schemas in the code through. We use alot of pydantic at work for this. You have your data schema class that is statically typed which you interact with and decide/encode it to json in the background.
All services expose an api to get JSON schemas from the apis so you can automatically generate the remote types used by other services when they change.
Using schemas for remote services has made life simpler for us so I would say schemas are a huge win. Not supporting JSON is not something I see happening anytime soon though, multiple parallel encodings based on schemas might be a possibility though.
So nowadays a new CPU might not be better at everything then the previous version but it will most likely have more cache and some internal improvements to pipelining/concurrency.
Given this, for newer versions it can be useful to add instructions to take advantage of extra pipelining or using a different instruction that happen to be faster now.
Browsers in general do often change with new temporary user facing features.
People choose iOS because it's a status symbol or they like the design of the interface. Not because they are afraid of updates.
So I don't think we will ever land in a situation where everyone uses the same thing.
Particles behave non-locally which is really really not cool :(. From that you only have a bad list of options to choose from...
Do you go for non-local hidden variables
Multiverse spawning photons
Super determinism
More dimensions perhaps? Maybe the problem goes away if you have 11