A Brighter 2021 With Virtual Binding (+ Good Riddance 2020)


(hmm, something's wrong with those fireworks :microbe: :microscope:)

There's no better way to push 2020 out the door than to hit the ground running for the new year...so...

I've Committed The Initial Virtual Binding Implementation To Master!

Please try throwing it some hardballs, in the web build or elsewhere. Some code paths trigger panics because I don't think they can happen in practice...so if you find out a way to make them happen, that's important to know. But so far it seems to be holding up, and performance is actually pretty decent--even though it's an early draft with basically no optimization. I'm betting it can get much better.

Why have I thought this is so important for so long? Virtual binding is to address the foundational problems of bindings being changed out from under users...when they should reasonably assume the arrays were under their control. I've pointed out catastrophic flaws like this one:

obj1: make object! [num: 10]
some-rule: [... num ...]
bind some-rule obj1  ; the context you intentionally want for the rule

obj2: make object! compose/only [
    rule: (some-rule),  ; mutably binds SOME-RULE to this object (!!!)
    some-field ...,
    num: ...  ; if any of these fields appear in SOME-RULE, you break it

some-rule  ; the bindings in this block are altered!

Historically, such code changes the global SOME-RULE itself--without you asking--and that's a recipe for disaster. This was pervasive in any construct that did binding behind-your-back (including USE and FOR-EACH).

Even with virtual binding stopping the worst of this as it is now, we should ask if obj2/rule should be viewed distinctly from SOME-RULE. I don't think viewing it differently by default is a great idea (which incidentally makes it CONST), and I've put forth some ideas for how to apply virtual binding to build different constructs to address the different meanings. The big picture isn't all put together yet...but reasonable answers seem well within reach, if we are persistent.

It's a major development, for which the foundations were laid over many steps...and seeing it come together is a fitting way to start the year.

Tech Aside, About the rest of that 2020 year...

By just about every metric available, this has been 365 days we could have done without. And after 2019's disappointment with the once-reliable StackOverflow, faceless robo-corporatism destroyed another guiding star... Travis CI poisoning itself with no voice to explain why it cut the line... forcing our scrappy efforts to bear the burden of adapting to a replacement. I've explained why this is not entirely bad, however.

With December hitting, I committed myself to working on virtual binding ("Virtual Binding's Last Stand") in the hopes of having something notable to announce today. That announcement could have been "None of this is going to work, so we should just give up on this broken language, and do something more productive with our lives." Unfortunately the efforts gave promising results, so we'll be here for at least a while longer. :stuck_out_tongue:

Another good thing that has happened here in the end of 2020 is there's been a notable uptick in design engagement. @gchiu attributes this to the fact that he's called webconference meetings--which may or may not be true. Either way, it makes all the difference in the world if experienced hands are around and committed to working through the details. Hence I hope @rgchris remains motivated enough to dot i's and cross t's...because we really can act swiftly on things, once we know what we want. Please let's finalize the issue regarding the VOID naming.

Besides what's gone down in the last month, more happened in 2020 than you might think...

Stackless May Not Have Been Merged, But It Was Quite Fleshed Out!

When setting directions for 2020, I sounded the alarm that stackless was a critical technical point. If each recursion in the interpreter corresponds to a recursion of the underlying machine stack, even non-"pathological" cases will run out of machine stack on "novel" platforms. WebAssembly is such a platform.

In fact: just this week, I wanted to point @okram at Graham's chess demo...but do <chess> called do <popupdemo>, and this level of nesting was enough to break the default stack settings with the new-ish "Asyncify" emscripten build. (DO is a complex function which layers on top of LOAD, which is a lot of usermode code, so nesting it inside of another DO/LOAD inside of a DO from the Replpad stack becomes quite a lot...if you realize each interpreter call is several C functions, producing several Wasm functions, multiplying to be much deeper than corresponding JavaScript recursions would be.)

So stackless is a critical change. There's no going back on it...the branch will be merged, but some of the experiments using it will not be mainlined yet. Whether that means we'll be condoning use of the generators and yielders in the near term is another matter. Hopefully so.

Stackless was a lot of where this year's energy went. That energy hasn't been wasted, and it has already had several bits integrated in phases...which will be an ongoing process.

A Lot Of Other Things Happened, Too.

There have been no shortage of interesting new behaviors.

  • We got a new COMMA! type, which I have come to think is really great.

  • ACTION!s and FRAME!s cache the known label in the cell, leading to better understandable stack traces and errors in APPLY-like situations. (Might seem a small thing, but it's a big win!)

  • NULL Isotopes solve the off-putting corruption of conditional branches that evaluate to NULL, while still allowing the existence ELSE and THEN and ALSO to work.

  • Invisibles ("void functions"?) are opportunistic, so you can make a function that decides while it's running to opt out of returning any value at all.

  • CHAR! and ISSUE! are unified, to the type that is likely to be named TOKEN!. I really want @rgchris to weigh in here, because I think this is a very solid direction for the type.

  • Generic TUPLE! is here, turning the previously kind-of-useless TUPLE! type into something that can be applied for interesting effects in dialects and the interpreter alike.

  • refinement-like PATH!s are now compressed, which solves one of the potential objections to the idea that /A be considered a "path", as it costs no more than a WORD! to represent.

  • Multiple-Return Values arrived as an application for SET-BLOCK!. While they aren't completely worked out, they have been working quite well as syntactic sugar over passing refinements WORD!s or PATH!s.

  • ENBIN and DEBIN arrived, and while they didn't take much to implement, I think they are a good beacon of how we can explain what's truly different about the kinds of solutions you might make in Ren-C vs. a traditional language.

  • All crypto and hashing transitioned to MBEDTLS. Mbedtls is pure C, philosophically aligned with our project goals, and modularized admirably. This gives us access to more algorithms with up-to-date vetting.

  • Predicates are starting to be implemented, which help parameterize algorithmic functions by means of a clever notation, taking advantage of generic TUPLE!. It's a novel approach to the idea which should hopefully help put more of the sometimes-arbitrary-seeming internal decision-making of generic code in the hands of the user.

  • BigNum and BITSET! Research. I haven't committed any of it into Ren-C, but I spent a good bit of time working on it (and becoming a contributor to a bitset library to prepare it for integration). I think we have interesting angles on both of these in the works.

I could go through the commit log and list a lot of other internal things...some of which are rather consequential (like using clever C++-build mechanisms to check at compile time to make sure the CONST/PROTECT bits are honored in cells, so that there aren't systemic bugs where C code forgets to check it and lets you mutate things you asked not to). But suffice to say there's a lot of little things, and just the maintenance of "another year passed and it still compiles and runs on the ever-evolving systems".

So What's In Store For 2021?

  • Kick the tires of virtual binding, optimize and clean it up as necessary

  • Hammer out MAKE OBJECT! / CLASS / METHOD and their variants in a way that satisfies the peoples and makes computational sense.

  • Integrate the stackless branch so the web build can breathe easier, and come up with satisfying answers to how suspended stacks interact with locking. Anyone with something to say about mutating while iterating needs to say it.

  • A renewed build system, with the outcome of being able to load Wasm "side-modules" as the WebAssembly equivalent to DLLs.

  • Debugging, stylized such that it can be done remotely between processes--even if one of those processes is running in Wasm in a browser, and one is not.

One of the big reasons I wanted to get stackless thought out is because of how much it impacted the idea of designing a good debugger. I thought stackless would help write a debugger (by letting you put the debugger on one stack and the user code on another). But any assistance you get from that is completely undermined by the problem of trying to write a debugger for stackless code.

So like I've been saying, I now think our first true debugger needs to be a remote debugger. It may seem to be rather constraining to say the debugger can't share memory with the debugged process...but if the debugger is written with that discipline, it can be run in-process as well as out-of-process. I think it's the right way to go.

In any case, I think the bets overall are the right ones. And I can feel more comfortable with Virtual Binding running, to think we might be able to mitigate some of the more egregious aspects of Rebol's Rube-Goldberg design.


Thank you @hostilefork for a productive year in Ren-C, which helped offset a year of historically crap proportions.
Crapfully yours,

HF does this with one hand tied behind his back!