...if you're lucky enough to be among the privileged.
Pros of Berlin:
- Good transport
- Bikeable
- Safe
- Cheaper than the big coastal cities in the US, with lower rent.
- Good clubbing (not my thing)
Cons of Berlin:
- Healthcare is inconvenient. Doctor's offices won't pick up the phone, and won't leave you on hold. You just have to go in person. Providers all work in small doctor-owned practices, and you get a referral runaround with huge wait times.
- The food in Germany is terrible. The quality of produce and other ingredients is very bad, and the restaurants are nothing special. One notable bright spot is the availability of vegetarian and vegan food. Also falafel and doner.
- The salaries are shockingly low. Really ask yourself if all the comforts of Europe are worth cutting your salary in 2 or 3, and that's before...
- Taxes. The top tax rate here is in the low-40s, comparable to the US, but unlike the US, the top tax bracket starts below $65k.
- Europe has an impending demographic crisis, and the social safety net they fund by plundering your paycheck probably won't be there for you when you retire.
- Stores in general suck. They have fewer, and worse products.
- Everyone still smokes here.
Only for rational numbers. Doesn't work for real and complex numbers.
> It's even a useful thing to do, how else would you define multiplication?
Axiomatically, not algorithmically.
One issue with this approach is that it doesn't really scale easily beyond a single server. You need something like the JVM which allows for closures to be sent between machines sharing the same code base. Plus, even in the JVM case, you must have the class files required by the closure available on the JVM which tries to run it.
I really think it is a better idea to just use a database and pass state explicitly rather than trying to do something fancy with continuations. However, continuations can be extremely useful for making the server asynchronous without making it look asynchronous.
While Promises are nice, I think they are severely flawed in that they must "infect" any code which tries to use them. For instance, I was dealing with some Typescript compiler interfaces a few years back which expected to be able to read files synchronously, something which does not hold true if you try to emulate a filesystem in the browser using web requests. With true continuations, it would be possible to simply pause this computation transparently and then resume it once the request was complete.
A workflow engine I recently built provided an interpreter for a Scheme-based language that, for each blocking operation, took a snapshot of the interpreter state (heap + stack) and persisted that to a database. Each time an operation completes (which could be after hours/days/weeks), the interpreter state is restored from the database and execution proceeds from the point at which it was previously suspended. The interpreter supports concurrency, allowing multiple blocking operations to be in progress at the same time, so the work to be done after the completion of one can proceed even while others remain blocked.
The advantage of doing this at the language level is that persistence becomes transparent to the programmer. No decorators are needed; every function and expression inherently has all the properties of a "step" as described here. Deterministic execution can be provided if needed. And if there's a need to call out to external code, it is possible to expose Python functions as Scheme built-ins that can be invoked from the interpreter either synchronously or asynchronously.
I see a lot of workflow engines released that almost get to the point of being like a traditional programming language interpreter but not quite, exposing the structure of the workflow using a DAG with explicit nodes/edges, or (in the case of DBOS) as decorators. While I think this is ok for some applications, I really believe the "workflow as a programming language" perspective deserves more attention.
There's a lot of really interesting work that's been done over the years on persistent systems, and especially orthogonal persistence, but sadly this has mostly remained confined to the research literature. Two real-world systems that do implement persistence at the language level are Ethereum and Smalltalk; also some of the older Lisp-based systems provided similar functionality. I think there's a lot more value waiting to be mined from these past efforts.