There are still fairly big fundamental holes in the model, where progress is chipped away slowly.
What drew my interest in Rebol initially was based on being puzzled about how it could work at all. I'd see something like:
rebol2>> foo: func [x y] [if x [do compose [1000 + (y)]]]
rebol2>> x: 5
rebol2>> y: 15
rebol2>> foo true [x + y]
== 1020 ; How did it know what I meant about which X and which Y?
When you can throw together simple examples like this so freely, and they generally seem to work (at first), it defies conventional wisdom...and you aren't sure exactly what the limits are.
Rejecting it out-of-hand because it isn't 100% built of typical formal principles could be like someone rejecting spreadsheets for the same kinds of reasons:
designer: "So you've got this grid of cells...the columns are marked with letters and the rows are marked with numbers. The user can fill data in a cell like a string or number. But if the cell starts with an equals sign, that can be a formula...referencing other cells. The program calculates the formulas and overlays the answer in the formula cells in the default view."
formalist: "That's a preposterous idea, that can be disproven with a simple example. What if cell A1 says it is =B1+50
, and cell B1 says it is =A1+50
. You'll get an infinite loop. Everyone knows you must separate your code from the data, and have the code checked for consistency in a compilation phase. This 'spreadsheet' is a waste of time, let me show you this pure functional language instead..."
But in terms of the mechanics, my opinion is that Rebol2 dead-ended rather quickly. The composability was so limited that you were rewriting the entire program and evaluation engine on nearly every change, because the language could not deliver. It was more of a "scriptable app" than a "language"...serving up a few features with a high dependence on Carl cracking open the C to deliver customizations that the small set of users needed that day.
(I'll point out that this way of thinking--that Rebol2 was an "app" tailored by its vendor to cater to the needs of certain users--manifested as a foray into wanting to turn Rebol Technologies into a consulting business. This concept is again being recycled by Red...with the idea of "we use it every day, it's a codebase we understand, so it's the lens through which we will solve your problem". But this doesn't really speak to the merits of the language for those who aren't years-deep in investing in its internal implementation--to the point it's the only thing they know how to edit anymore.)
The brokenness of returns was an early example of "unfit for purpose"...and it's something Ren-C addresses. (Here's a link to the point in a video where I explain definitional returns, and if you watch that whole video for context it hits a lot of points of the progress so far on various issues).
ren-c>> unless: function [cond block] [if not cond (block)]
ren-c>> bar: function [x] [unless x = 10 [return "not 10"] return "it's 10!"]
ren-c>> bar 20
== "not 10" ; right answer (Rebol2, Red, R3-Alpha say "it's 10")
Some things like this need to be gotten right, otherwise people might as well use Red and accept that the flaws are so intrinsic to their design that it's going to be broken forever. (I can't serve the audience who will accept broken forever as an answer, because I'll never be able to compete with the rate at which garbage can be written.)
There are still more of these questions, where the mechanical issue underlying it is so basic that it would impact every piece of code written. There's no point in having people write a lot of deployment code if the rug is going to be yanked out from under them later.
But decisions will have to be made at some point on saying "that's as good as this version is going to be". What I want the first audience to be is code golfers, as a way of bringing in other ambitious designers to the project to contribute to the open areas before things are fully firmed up. Moving on to at least that phase has to happen somewhat soon.