It's obviously not enough to be able to "project into the future", but it's pretty awesome for looking at what happened. It's also a great way to maintain discipline for your code -- we're already off on a wild tangent here, so I won't elaborate.
> I'm curious though, why you suggest for a language to work like this you have to abandon Turing Completeness
You don't necessarily have to, as long as you a) assume complete purity (as in e.g. Haskell's ST monad), and b) are resigned to having to actually run all the computations when running "forward".
Keep in mind that some of those computations may be EXPTIME... but as long as you can interrupt them, then I suppose that's OK.
I think the conclusion is that anything TC that doesn't do side-effects would basically be OK (as in: not actively wrong), but not necessarily practical in our lifetime. Timeouts might work here, actually.
"Simulate the system" means "execute normally" for all practical purposes. That's what TC + Halting Problem[1] essentially boils down to, absent other knowledge about the program. Hence my suggestion to let the program itself do "projection" because it could potentially be hugely more efficient, and possible (but perhaps with bad "fidelity" in the case of side-effecting computation).
Anyway... to the larger point and to expound a little:
If everything is pure, then there's basically no problem (except computational cost), but imagine our Mario is taking part in a multiplayer game.
What do you think should happen?
(Obviously, this is not realistic for the reason that you usally don't run "debuggers" or "IDEs" in a 'multiplayer' scenario, but I think the analogy holds in general. Imagine that the other players' actions are I/O operations like "what's the current time?" or "talk to a REST service", etc.)
Most interesting programs do this kind of thing all the time. Of course, there are interesting programs/functions which are purely algorithmic and rewind/fast-forward should work for them, but they are mostly pretty niche compared to most of the programming that currently happening.
A very interesting example that's somewhere "in between" is Haskell's STM monad which does have very controlled side effects and where you can just "retry" and particular computation in case synchronization fails, but it still doesn't allow you to "project".
[1] Alright, I suppose it's just undeciability for non-trivial properties of TCs languages, but Halting Problem is a convenient shorthand.
> that wall being the limitations of programming languages you outline here
Exactly. I was thinking about the same a while ago. EVE is an attempt to build a new reality where those limitations are gone. But it didn't work quite well -- in order to get support, money, users it should be somehow connected to production.
There is a platform where all this complexety with IO (the mail send in your example) is abstracted quite nicely and can be manipulated/mocked: the BEAM platform (Erlang, Elixir).
You can record IO for particular process (it just messages), replay it if you want.
Also, modules can be compiled in any order, functions in module can be defined in any order. It's much easier to treat function as smallest unit of code. To create a parser that could transform code into data, allow it to manipulate (structured editing and all) and transform it back to text form, to be used by other programmers.
I think if LightTable was aiming at BEAM platform it could go a bit further. Utilize growing popularity of Elixir, and create a new development platform.
After writing countless programs in this style, which is very different from conventional programming, I have to say the Mario example is a nice demo, but in reality we didn't find time-travel useful in scenarios like that. What was infinitely useful though, was being able to trace the provenance of different values in your program for debugging. Since we kept information around that the compiler usually throws away, we could tell you exactly how a value or UI element was calculated, and give you tools for interacting with that history that just aren't possible in other languages. For instance, you could encounter a bug, pack up the state of your session, send that over to another dev, and he/she would see exactly the environment in which your code was executing.
You bring up the good point that not everything is written in this way, and so interacting with external code can be tricky. For example, you might have some code that sends out an email every time the system memory reaches a threshold. Now, you might get an e-mail you didn't expect, but you could go back and see exactly why that email was sent, and deduce the bug through the provenance tree.
As I said earlier, after writing programs in this style for 3 years, I'm utterly convinced we won't be programming in the future the way we program today. There were versions of Eve where we wrote very complex applications, from webapps to robotics, that didn't even feel like programming -- it felt more like forming a shape out of clay, where the clay in this case is a digital "material".
In the end, Eve couldn't get more funding because it wasn't a venture that was really set up to fit into the VC mold (and I'm still not sure how Chris and Rob convinced VCs to fund them in the first place), but I'm absolutely sure the current way of doing things will fade with time. It's going to take a lot more research and a lot more convincing, because there are a lot of people out there that for some reason don't want to see projects like this work, but as someone who went down the rabbit hole and gotten a glimpse of this future, I really just can't fathom how humans could be working with languages held back with so much baggage from the early days of computing in the year 2100 for example.
I'm curious though, why you suggest for a language to work like this you have to abandon Turing Completeness. This wasn't my experience at all, and we implemented a Turing Machine in Eve just to prove we were TC (http://incidentalcomplexity.com/2014/12/01/nov/).